@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/server/index.js
CHANGED
|
@@ -42,6 +42,12 @@ var __export = (target, all) => {
|
|
|
42
42
|
};
|
|
43
43
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
44
44
|
|
|
45
|
+
// node_modules/tsup/assets/cjs_shims.js
|
|
46
|
+
var init_cjs_shims = __esm({
|
|
47
|
+
"node_modules/tsup/assets/cjs_shims.js"() {
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
|
|
45
51
|
// src/server/storage/redis.ts
|
|
46
52
|
var redis_exports = {};
|
|
47
53
|
__export(redis_exports, {
|
|
@@ -117,6 +123,7 @@ async function closeRedis() {
|
|
|
117
123
|
var redisInstance, redis;
|
|
118
124
|
var init_redis = __esm({
|
|
119
125
|
"src/server/storage/redis.ts"() {
|
|
126
|
+
init_cjs_shims();
|
|
120
127
|
redisInstance = null;
|
|
121
128
|
redis = new Proxy({}, {
|
|
122
129
|
get(_target, prop) {
|
|
@@ -133,10 +140,34 @@ var init_redis = __esm({
|
|
|
133
140
|
}
|
|
134
141
|
});
|
|
135
142
|
|
|
143
|
+
// src/server/index.ts
|
|
144
|
+
init_cjs_shims();
|
|
145
|
+
|
|
146
|
+
// src/server/mcp/oauth-client.ts
|
|
147
|
+
init_cjs_shims();
|
|
148
|
+
|
|
149
|
+
// src/server/mcp/storage-oauth-provider.ts
|
|
150
|
+
init_cjs_shims();
|
|
151
|
+
|
|
152
|
+
// src/server/storage/index.ts
|
|
153
|
+
init_cjs_shims();
|
|
154
|
+
|
|
155
|
+
// src/server/storage/redis-backend.ts
|
|
156
|
+
init_cjs_shims();
|
|
157
|
+
|
|
136
158
|
// src/shared/constants.ts
|
|
159
|
+
init_cjs_shims();
|
|
137
160
|
var SESSION_TTL_SECONDS = 43200;
|
|
138
161
|
var STATE_EXPIRATION_MS = 10 * 60 * 1e3;
|
|
139
162
|
var TOKEN_EXPIRY_BUFFER_MS = 5 * 60 * 1e3;
|
|
163
|
+
var DEFAULT_CLIENT_NAME = "MCP Assistant";
|
|
164
|
+
var DEFAULT_CLIENT_URI = "https://mcp-assistant.in";
|
|
165
|
+
var DEFAULT_LOGO_URI = "https://mcp-assistant.in/logo.svg";
|
|
166
|
+
var DEFAULT_POLICY_URI = "https://mcp-assistant.in/privacy";
|
|
167
|
+
var SOFTWARE_ID = "@mcp-ts";
|
|
168
|
+
var SOFTWARE_VERSION = "1.3.4";
|
|
169
|
+
var MCP_CLIENT_NAME = "mcp-ts-oauth-client";
|
|
170
|
+
var MCP_CLIENT_VERSION = "2.0";
|
|
140
171
|
|
|
141
172
|
// src/server/storage/redis-backend.ts
|
|
142
173
|
var firstChar = nanoid.customAlphabet(
|
|
@@ -152,6 +183,16 @@ var RedisStorageBackend = class {
|
|
|
152
183
|
this.redis = redis2;
|
|
153
184
|
__publicField(this, "DEFAULT_TTL", SESSION_TTL_SECONDS);
|
|
154
185
|
__publicField(this, "KEY_PREFIX", "mcp:session:");
|
|
186
|
+
__publicField(this, "IDENTITY_KEY_PREFIX", "mcp:identity:");
|
|
187
|
+
__publicField(this, "IDENTITY_KEY_SUFFIX", ":sessions");
|
|
188
|
+
}
|
|
189
|
+
async init() {
|
|
190
|
+
try {
|
|
191
|
+
await this.redis.ping();
|
|
192
|
+
console.log("[mcp-ts][Storage] Redis: \u2713 Connected to server.");
|
|
193
|
+
} catch (error) {
|
|
194
|
+
throw new Error(`[RedisStorage] Failed to connect to Redis: ${error.message}`);
|
|
195
|
+
}
|
|
155
196
|
}
|
|
156
197
|
/**
|
|
157
198
|
* Generates Redis key for a specific session
|
|
@@ -165,7 +206,34 @@ var RedisStorageBackend = class {
|
|
|
165
206
|
* @private
|
|
166
207
|
*/
|
|
167
208
|
getIdentityKey(identity) {
|
|
168
|
-
return
|
|
209
|
+
return `${this.IDENTITY_KEY_PREFIX}${identity}${this.IDENTITY_KEY_SUFFIX}`;
|
|
210
|
+
}
|
|
211
|
+
parseIdentityFromKey(identityKey) {
|
|
212
|
+
return identityKey.slice(
|
|
213
|
+
this.IDENTITY_KEY_PREFIX.length,
|
|
214
|
+
identityKey.length - this.IDENTITY_KEY_SUFFIX.length
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
async scanKeys(pattern) {
|
|
218
|
+
const redis2 = this.redis;
|
|
219
|
+
if (typeof redis2.scan !== "function") {
|
|
220
|
+
return await this.redis.keys(pattern);
|
|
221
|
+
}
|
|
222
|
+
const keys = /* @__PURE__ */ new Set();
|
|
223
|
+
let cursor = "0";
|
|
224
|
+
try {
|
|
225
|
+
do {
|
|
226
|
+
const [nextCursor, batch] = await redis2.scan(cursor, "MATCH", pattern, "COUNT", 100);
|
|
227
|
+
cursor = nextCursor;
|
|
228
|
+
for (const key of batch) {
|
|
229
|
+
keys.add(key);
|
|
230
|
+
}
|
|
231
|
+
} while (cursor !== "0");
|
|
232
|
+
} catch (error) {
|
|
233
|
+
console.warn("[RedisStorage] SCAN failed, falling back to KEYS:", error);
|
|
234
|
+
return await this.redis.keys(pattern);
|
|
235
|
+
}
|
|
236
|
+
return Array.from(keys);
|
|
169
237
|
}
|
|
170
238
|
generateSessionId() {
|
|
171
239
|
return firstChar() + rest();
|
|
@@ -233,17 +301,13 @@ var RedisStorageBackend = class {
|
|
|
233
301
|
}
|
|
234
302
|
}
|
|
235
303
|
async getIdentityMcpSessions(identity) {
|
|
236
|
-
const
|
|
237
|
-
|
|
238
|
-
return await this.redis.smembers(identityKey);
|
|
239
|
-
} catch (error) {
|
|
240
|
-
console.error(`[RedisStorage] Failed to get sessions for ${identity}:`, error);
|
|
241
|
-
return [];
|
|
242
|
-
}
|
|
304
|
+
const sessions = await this.getIdentitySessionsData(identity);
|
|
305
|
+
return sessions.map((session) => session.sessionId);
|
|
243
306
|
}
|
|
244
307
|
async getIdentitySessionsData(identity) {
|
|
245
308
|
try {
|
|
246
|
-
const
|
|
309
|
+
const identityKey = this.getIdentityKey(identity);
|
|
310
|
+
const sessionIds = await this.redis.smembers(identityKey);
|
|
247
311
|
if (sessionIds.length === 0) return [];
|
|
248
312
|
const results = await Promise.all(
|
|
249
313
|
sessionIds.map(async (sessionId) => {
|
|
@@ -251,6 +315,10 @@ var RedisStorageBackend = class {
|
|
|
251
315
|
return data ? JSON.parse(data) : null;
|
|
252
316
|
})
|
|
253
317
|
);
|
|
318
|
+
const staleSessionIds = sessionIds.filter((_, index) => results[index] === null);
|
|
319
|
+
if (staleSessionIds.length > 0) {
|
|
320
|
+
await this.redis.srem(identityKey, ...staleSessionIds);
|
|
321
|
+
}
|
|
254
322
|
return results.filter((session) => session !== null);
|
|
255
323
|
} catch (error) {
|
|
256
324
|
console.error(`[RedisStorage] Failed to get session data for ${identity}:`, error);
|
|
@@ -269,9 +337,22 @@ var RedisStorageBackend = class {
|
|
|
269
337
|
}
|
|
270
338
|
async getAllSessionIds() {
|
|
271
339
|
try {
|
|
272
|
-
const
|
|
273
|
-
const
|
|
274
|
-
|
|
340
|
+
const keys = await this.scanKeys(`${this.KEY_PREFIX}*`);
|
|
341
|
+
const sessions = await Promise.all(
|
|
342
|
+
keys.map(async (key) => {
|
|
343
|
+
const data = await this.redis.get(key);
|
|
344
|
+
if (!data) {
|
|
345
|
+
return null;
|
|
346
|
+
}
|
|
347
|
+
try {
|
|
348
|
+
return JSON.parse(data).sessionId;
|
|
349
|
+
} catch (error) {
|
|
350
|
+
console.error("[RedisStorage] Failed to parse session while listing all session IDs:", error);
|
|
351
|
+
return null;
|
|
352
|
+
}
|
|
353
|
+
})
|
|
354
|
+
);
|
|
355
|
+
return sessions.filter((sessionId) => sessionId !== null);
|
|
275
356
|
} catch (error) {
|
|
276
357
|
console.error("[RedisStorage] Failed to get all sessions:", error);
|
|
277
358
|
return [];
|
|
@@ -279,10 +360,11 @@ var RedisStorageBackend = class {
|
|
|
279
360
|
}
|
|
280
361
|
async clearAll() {
|
|
281
362
|
try {
|
|
282
|
-
const
|
|
283
|
-
const
|
|
284
|
-
|
|
285
|
-
|
|
363
|
+
const keys = await this.scanKeys(`${this.KEY_PREFIX}*`);
|
|
364
|
+
const identityKeys = await this.scanKeys(`${this.IDENTITY_KEY_PREFIX}*${this.IDENTITY_KEY_SUFFIX}`);
|
|
365
|
+
const allKeys = [...keys, ...identityKeys];
|
|
366
|
+
if (allKeys.length > 0) {
|
|
367
|
+
await this.redis.del(...allKeys);
|
|
286
368
|
}
|
|
287
369
|
} catch (error) {
|
|
288
370
|
console.error("[RedisStorage] Failed to clear sessions:", error);
|
|
@@ -290,12 +372,24 @@ var RedisStorageBackend = class {
|
|
|
290
372
|
}
|
|
291
373
|
async cleanupExpiredSessions() {
|
|
292
374
|
try {
|
|
293
|
-
const
|
|
294
|
-
const
|
|
295
|
-
|
|
296
|
-
const
|
|
297
|
-
if (
|
|
298
|
-
await this.redis.del(
|
|
375
|
+
const identityKeys = await this.scanKeys(`${this.IDENTITY_KEY_PREFIX}*${this.IDENTITY_KEY_SUFFIX}`);
|
|
376
|
+
for (const identityKey of identityKeys) {
|
|
377
|
+
const identity = this.parseIdentityFromKey(identityKey);
|
|
378
|
+
const sessionIds = await this.redis.smembers(identityKey);
|
|
379
|
+
if (sessionIds.length === 0) {
|
|
380
|
+
await this.redis.del(identityKey);
|
|
381
|
+
continue;
|
|
382
|
+
}
|
|
383
|
+
const existenceChecks = await Promise.all(
|
|
384
|
+
sessionIds.map((sessionId) => this.redis.exists(this.getSessionKey(identity, sessionId)))
|
|
385
|
+
);
|
|
386
|
+
const staleSessionIds = sessionIds.filter((_, index) => existenceChecks[index] === 0);
|
|
387
|
+
if (staleSessionIds.length > 0) {
|
|
388
|
+
await this.redis.srem(identityKey, ...staleSessionIds);
|
|
389
|
+
}
|
|
390
|
+
const remainingCount = await this.redis.scard(identityKey);
|
|
391
|
+
if (remainingCount === 0) {
|
|
392
|
+
await this.redis.del(identityKey);
|
|
299
393
|
}
|
|
300
394
|
}
|
|
301
395
|
} catch (error) {
|
|
@@ -310,6 +404,9 @@ var RedisStorageBackend = class {
|
|
|
310
404
|
}
|
|
311
405
|
}
|
|
312
406
|
};
|
|
407
|
+
|
|
408
|
+
// src/server/storage/memory-backend.ts
|
|
409
|
+
init_cjs_shims();
|
|
313
410
|
var firstChar2 = nanoid.customAlphabet(
|
|
314
411
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
|
|
315
412
|
1
|
|
@@ -325,6 +422,9 @@ var MemoryStorageBackend = class {
|
|
|
325
422
|
// Map<identity, Set<sessionId>>
|
|
326
423
|
__publicField(this, "identitySessions", /* @__PURE__ */ new Map());
|
|
327
424
|
}
|
|
425
|
+
async init() {
|
|
426
|
+
console.log("[mcp-ts][Storage] Memory: \u2713 internal memory store active.");
|
|
427
|
+
}
|
|
328
428
|
getSessionKey(identity, sessionId) {
|
|
329
429
|
return `${identity}:${sessionId}`;
|
|
330
430
|
}
|
|
@@ -400,6 +500,9 @@ var MemoryStorageBackend = class {
|
|
|
400
500
|
async disconnect() {
|
|
401
501
|
}
|
|
402
502
|
};
|
|
503
|
+
|
|
504
|
+
// src/server/storage/file-backend.ts
|
|
505
|
+
init_cjs_shims();
|
|
403
506
|
var firstChar3 = nanoid.customAlphabet(
|
|
404
507
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
|
|
405
508
|
1
|
|
@@ -444,6 +547,7 @@ var FileStorageBackend = class {
|
|
|
444
547
|
}
|
|
445
548
|
}
|
|
446
549
|
this.initialized = true;
|
|
550
|
+
console.log(`[mcp-ts][Storage] File: \u2713 storage directory at ${path__namespace.dirname(this.filePath)} verified.`);
|
|
447
551
|
}
|
|
448
552
|
async ensureInitialized() {
|
|
449
553
|
if (!this.initialized) await this.init();
|
|
@@ -520,6 +624,9 @@ var FileStorageBackend = class {
|
|
|
520
624
|
async disconnect() {
|
|
521
625
|
}
|
|
522
626
|
};
|
|
627
|
+
|
|
628
|
+
// src/server/storage/sqlite-backend.ts
|
|
629
|
+
init_cjs_shims();
|
|
523
630
|
var SqliteStorage = class {
|
|
524
631
|
constructor(options = {}) {
|
|
525
632
|
__publicField(this, "db", null);
|
|
@@ -548,6 +655,7 @@ var SqliteStorage = class {
|
|
|
548
655
|
CREATE INDEX IF NOT EXISTS idx_${this.table}_identity ON ${this.table}(identity);
|
|
549
656
|
`);
|
|
550
657
|
this.initialized = true;
|
|
658
|
+
console.log(`[mcp-ts][Storage] SQLite: \u2713 database at ${this.dbPath} verified.`);
|
|
551
659
|
} catch (error) {
|
|
552
660
|
if (error.code === "MODULE_NOT_FOUND" || error.message?.includes("better-sqlite3")) {
|
|
553
661
|
throw new Error(
|
|
@@ -663,9 +771,170 @@ var SqliteStorage = class {
|
|
|
663
771
|
}
|
|
664
772
|
};
|
|
665
773
|
|
|
774
|
+
// src/server/storage/supabase-backend.ts
|
|
775
|
+
init_cjs_shims();
|
|
776
|
+
var SupabaseStorageBackend = class {
|
|
777
|
+
constructor(supabase) {
|
|
778
|
+
this.supabase = supabase;
|
|
779
|
+
__publicField(this, "DEFAULT_TTL", SESSION_TTL_SECONDS);
|
|
780
|
+
}
|
|
781
|
+
async init() {
|
|
782
|
+
const { error } = await this.supabase.from("mcp_sessions").select("session_id").limit(0);
|
|
783
|
+
if (error) {
|
|
784
|
+
if (error.code === "42P01") {
|
|
785
|
+
throw new Error(
|
|
786
|
+
'[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.'
|
|
787
|
+
);
|
|
788
|
+
}
|
|
789
|
+
throw new Error(`[SupabaseStorage] Initialization check failed: ${error.message}`);
|
|
790
|
+
}
|
|
791
|
+
console.log('[mcp-ts][Storage] Supabase: \u2713 "mcp_sessions" table verified.');
|
|
792
|
+
}
|
|
793
|
+
generateSessionId() {
|
|
794
|
+
return crypto.randomUUID();
|
|
795
|
+
}
|
|
796
|
+
mapRowToSessionData(row) {
|
|
797
|
+
return {
|
|
798
|
+
sessionId: row.session_id,
|
|
799
|
+
serverId: row.server_id,
|
|
800
|
+
serverName: row.server_name,
|
|
801
|
+
serverUrl: row.server_url,
|
|
802
|
+
transportType: row.transport_type,
|
|
803
|
+
callbackUrl: row.callback_url,
|
|
804
|
+
createdAt: new Date(row.created_at).getTime(),
|
|
805
|
+
identity: row.identity,
|
|
806
|
+
headers: row.headers,
|
|
807
|
+
active: row.active,
|
|
808
|
+
clientInformation: row.client_information,
|
|
809
|
+
tokens: row.tokens,
|
|
810
|
+
codeVerifier: row.code_verifier,
|
|
811
|
+
clientId: row.client_id
|
|
812
|
+
};
|
|
813
|
+
}
|
|
814
|
+
async createSession(session, ttl) {
|
|
815
|
+
const { sessionId, identity } = session;
|
|
816
|
+
if (!sessionId || !identity) throw new Error("identity and sessionId required");
|
|
817
|
+
const effectiveTtl = ttl ?? this.DEFAULT_TTL;
|
|
818
|
+
const expiresAt = new Date(Date.now() + effectiveTtl * 1e3).toISOString();
|
|
819
|
+
const { error } = await this.supabase.from("mcp_sessions").insert({
|
|
820
|
+
session_id: sessionId,
|
|
821
|
+
user_id: identity,
|
|
822
|
+
// Maps user_id to identity to support RLS using auth.uid()
|
|
823
|
+
server_id: session.serverId,
|
|
824
|
+
server_name: session.serverName,
|
|
825
|
+
server_url: session.serverUrl,
|
|
826
|
+
transport_type: session.transportType,
|
|
827
|
+
callback_url: session.callbackUrl,
|
|
828
|
+
created_at: new Date(session.createdAt || Date.now()).toISOString(),
|
|
829
|
+
identity,
|
|
830
|
+
headers: session.headers,
|
|
831
|
+
active: session.active ?? false,
|
|
832
|
+
client_information: session.clientInformation,
|
|
833
|
+
tokens: session.tokens,
|
|
834
|
+
code_verifier: session.codeVerifier,
|
|
835
|
+
client_id: session.clientId,
|
|
836
|
+
expires_at: expiresAt
|
|
837
|
+
});
|
|
838
|
+
if (error) {
|
|
839
|
+
if (error.code === "23505") {
|
|
840
|
+
throw new Error(`Session ${sessionId} already exists`);
|
|
841
|
+
}
|
|
842
|
+
throw new Error(`Failed to create session in Supabase: ${error.message}`);
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
async updateSession(identity, sessionId, data, ttl) {
|
|
846
|
+
const effectiveTtl = ttl ?? this.DEFAULT_TTL;
|
|
847
|
+
const expiresAt = new Date(Date.now() + effectiveTtl * 1e3).toISOString();
|
|
848
|
+
const updateData = {
|
|
849
|
+
expires_at: expiresAt,
|
|
850
|
+
updated_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
851
|
+
};
|
|
852
|
+
if ("serverId" in data) updateData.server_id = data.serverId;
|
|
853
|
+
if ("serverName" in data) updateData.server_name = data.serverName;
|
|
854
|
+
if ("serverUrl" in data) updateData.server_url = data.serverUrl;
|
|
855
|
+
if ("transportType" in data) updateData.transport_type = data.transportType;
|
|
856
|
+
if ("callbackUrl" in data) updateData.callback_url = data.callbackUrl;
|
|
857
|
+
if ("active" in data) updateData.active = data.active;
|
|
858
|
+
if ("headers" in data) updateData.headers = data.headers;
|
|
859
|
+
if ("clientInformation" in data) updateData.client_information = data.clientInformation;
|
|
860
|
+
if ("tokens" in data) updateData.tokens = data.tokens;
|
|
861
|
+
if ("codeVerifier" in data) updateData.code_verifier = data.codeVerifier;
|
|
862
|
+
if ("clientId" in data) updateData.client_id = data.clientId;
|
|
863
|
+
const { data: updatedRows, error } = await this.supabase.from("mcp_sessions").update(updateData).eq("identity", identity).eq("session_id", sessionId).select("id");
|
|
864
|
+
if (error) {
|
|
865
|
+
throw new Error(`Failed to update session: ${error.message}`);
|
|
866
|
+
}
|
|
867
|
+
if (!updatedRows || updatedRows.length === 0) {
|
|
868
|
+
throw new Error(`Session ${sessionId} not found for identity ${identity}`);
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
async getSession(identity, sessionId) {
|
|
872
|
+
const { data, error } = await this.supabase.from("mcp_sessions").select("*").eq("identity", identity).eq("session_id", sessionId).maybeSingle();
|
|
873
|
+
if (error) {
|
|
874
|
+
console.error("[SupabaseStorage] Failed to get session:", error);
|
|
875
|
+
return null;
|
|
876
|
+
}
|
|
877
|
+
if (!data) return null;
|
|
878
|
+
return this.mapRowToSessionData(data);
|
|
879
|
+
}
|
|
880
|
+
async getIdentitySessionsData(identity) {
|
|
881
|
+
const { data, error } = await this.supabase.from("mcp_sessions").select("*").eq("identity", identity);
|
|
882
|
+
if (error) {
|
|
883
|
+
console.error(`[SupabaseStorage] Failed to get session data for ${identity}:`, error);
|
|
884
|
+
return [];
|
|
885
|
+
}
|
|
886
|
+
return data.map((row) => this.mapRowToSessionData(row));
|
|
887
|
+
}
|
|
888
|
+
async removeSession(identity, sessionId) {
|
|
889
|
+
const { error } = await this.supabase.from("mcp_sessions").delete().eq("identity", identity).eq("session_id", sessionId);
|
|
890
|
+
if (error) {
|
|
891
|
+
console.error("[SupabaseStorage] Failed to remove session:", error);
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
async getIdentityMcpSessions(identity) {
|
|
895
|
+
const { data, error } = await this.supabase.from("mcp_sessions").select("session_id").eq("identity", identity);
|
|
896
|
+
if (error) {
|
|
897
|
+
console.error(`[SupabaseStorage] Failed to get sessions for ${identity}:`, error);
|
|
898
|
+
return [];
|
|
899
|
+
}
|
|
900
|
+
return data.map((row) => row.session_id);
|
|
901
|
+
}
|
|
902
|
+
async getAllSessionIds() {
|
|
903
|
+
const { data, error } = await this.supabase.from("mcp_sessions").select("session_id");
|
|
904
|
+
if (error) {
|
|
905
|
+
console.error("[SupabaseStorage] Failed to get all sessions:", error);
|
|
906
|
+
return [];
|
|
907
|
+
}
|
|
908
|
+
return data.map((row) => row.session_id);
|
|
909
|
+
}
|
|
910
|
+
async clearAll() {
|
|
911
|
+
const { error } = await this.supabase.from("mcp_sessions").delete().neq("session_id", "");
|
|
912
|
+
if (error) {
|
|
913
|
+
console.error("[SupabaseStorage] Failed to clear sessions:", error);
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
async cleanupExpiredSessions() {
|
|
917
|
+
const { error } = await this.supabase.from("mcp_sessions").delete().lt("expires_at", (/* @__PURE__ */ new Date()).toISOString());
|
|
918
|
+
if (error) {
|
|
919
|
+
console.error("[SupabaseStorage] Failed to cleanup expired sessions:", error);
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
async disconnect() {
|
|
923
|
+
}
|
|
924
|
+
};
|
|
925
|
+
|
|
926
|
+
// src/server/storage/types.ts
|
|
927
|
+
init_cjs_shims();
|
|
928
|
+
|
|
666
929
|
// src/server/storage/index.ts
|
|
667
930
|
var storageInstance = null;
|
|
668
931
|
var storagePromise = null;
|
|
932
|
+
async function initializeStorage(store) {
|
|
933
|
+
if (typeof store.init === "function") {
|
|
934
|
+
await store.init();
|
|
935
|
+
}
|
|
936
|
+
return store;
|
|
937
|
+
}
|
|
669
938
|
async function createStorage() {
|
|
670
939
|
const type = process.env.MCP_TS_STORAGE_TYPE?.toLowerCase();
|
|
671
940
|
if (type === "redis") {
|
|
@@ -675,68 +944,95 @@ async function createStorage() {
|
|
|
675
944
|
try {
|
|
676
945
|
const { getRedis: getRedis2 } = await Promise.resolve().then(() => (init_redis(), redis_exports));
|
|
677
946
|
const redis2 = await getRedis2();
|
|
678
|
-
console.log(
|
|
679
|
-
return new RedisStorageBackend(redis2);
|
|
947
|
+
console.log('[mcp-ts][Storage] Explicit selection: "redis"');
|
|
948
|
+
return await initializeStorage(new RedisStorageBackend(redis2));
|
|
680
949
|
} catch (error) {
|
|
681
|
-
console.error("[Storage] Failed to initialize Redis:", error.message);
|
|
682
|
-
console.log("[Storage] Falling back to In-Memory storage");
|
|
683
|
-
return new MemoryStorageBackend();
|
|
950
|
+
console.error("[mcp-ts][Storage] Failed to initialize Redis:", error.message);
|
|
951
|
+
console.log("[mcp-ts][Storage] Falling back to In-Memory storage");
|
|
952
|
+
return await initializeStorage(new MemoryStorageBackend());
|
|
684
953
|
}
|
|
685
954
|
}
|
|
686
955
|
if (type === "file") {
|
|
687
956
|
const filePath = process.env.MCP_TS_STORAGE_FILE;
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
}
|
|
691
|
-
console.log(`[Storage] Using File storage (${filePath}) (Explicit)`);
|
|
692
|
-
const store = new FileStorageBackend({ path: filePath });
|
|
693
|
-
store.init().catch((err) => console.error("[Storage] Failed to initialize file storage:", err));
|
|
694
|
-
return store;
|
|
957
|
+
console.log(`[mcp-ts][Storage] Explicit selection: "file" (${filePath || "default"})`);
|
|
958
|
+
return await initializeStorage(new FileStorageBackend({ path: filePath }));
|
|
695
959
|
}
|
|
696
960
|
if (type === "sqlite") {
|
|
697
961
|
const dbPath = process.env.MCP_TS_STORAGE_SQLITE_PATH;
|
|
698
|
-
console.log(`[Storage]
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
962
|
+
console.log(`[mcp-ts][Storage] Explicit selection: "sqlite" (${dbPath || "default"})`);
|
|
963
|
+
return await initializeStorage(new SqliteStorage({ path: dbPath }));
|
|
964
|
+
}
|
|
965
|
+
if (type === "supabase") {
|
|
966
|
+
const url = process.env.SUPABASE_URL;
|
|
967
|
+
const key = process.env.SUPABASE_SERVICE_ROLE_KEY || process.env.SUPABASE_ANON_KEY;
|
|
968
|
+
if (!url || !key) {
|
|
969
|
+
console.warn('[mcp-ts][Storage] Explicit selection "supabase" requires SUPABASE_URL and SUPABASE_SERVICE_ROLE_KEY.');
|
|
970
|
+
} else {
|
|
971
|
+
if (!process.env.SUPABASE_SERVICE_ROLE_KEY) {
|
|
972
|
+
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.');
|
|
973
|
+
}
|
|
974
|
+
try {
|
|
975
|
+
const { createClient } = await import('@supabase/supabase-js');
|
|
976
|
+
const client = createClient(url, key);
|
|
977
|
+
console.log('[mcp-ts][Storage] Explicit selection: "supabase"');
|
|
978
|
+
return await initializeStorage(new SupabaseStorageBackend(client));
|
|
979
|
+
} catch (error) {
|
|
980
|
+
console.error("[mcp-ts][Storage] Failed to initialize Supabase:", error.message);
|
|
981
|
+
console.log("[mcp-ts][Storage] Falling back to In-Memory storage");
|
|
982
|
+
return await initializeStorage(new MemoryStorageBackend());
|
|
983
|
+
}
|
|
984
|
+
}
|
|
702
985
|
}
|
|
703
986
|
if (type === "memory") {
|
|
704
|
-
console.log(
|
|
705
|
-
return new MemoryStorageBackend();
|
|
987
|
+
console.log('[mcp-ts][Storage] Explicit selection: "memory"');
|
|
988
|
+
return await initializeStorage(new MemoryStorageBackend());
|
|
706
989
|
}
|
|
707
990
|
if (process.env.REDIS_URL) {
|
|
708
991
|
try {
|
|
709
992
|
const { getRedis: getRedis2 } = await Promise.resolve().then(() => (init_redis(), redis_exports));
|
|
710
993
|
const redis2 = await getRedis2();
|
|
711
|
-
console.log(
|
|
712
|
-
return new RedisStorageBackend(redis2);
|
|
994
|
+
console.log('[mcp-ts][Storage] Auto-detection: "redis" (via REDIS_URL)');
|
|
995
|
+
return await initializeStorage(new RedisStorageBackend(redis2));
|
|
713
996
|
} catch (error) {
|
|
714
|
-
console.error("[Storage] Redis auto-detection failed:", error.message);
|
|
715
|
-
console.log("[Storage] Falling back to
|
|
716
|
-
return new MemoryStorageBackend();
|
|
997
|
+
console.error("[mcp-ts][Storage] Redis auto-detection failed:", error.message);
|
|
998
|
+
console.log("[mcp-ts][Storage] Falling back to next available backend");
|
|
717
999
|
}
|
|
718
1000
|
}
|
|
719
1001
|
if (process.env.MCP_TS_STORAGE_FILE) {
|
|
720
|
-
console.log(`[Storage] Auto-
|
|
721
|
-
|
|
722
|
-
store.init().catch((err) => console.error("[Storage] Failed to initialize file storage:", err));
|
|
723
|
-
return store;
|
|
1002
|
+
console.log(`[mcp-ts][Storage] Auto-detection: "file" (${process.env.MCP_TS_STORAGE_FILE})`);
|
|
1003
|
+
return await initializeStorage(new FileStorageBackend({ path: process.env.MCP_TS_STORAGE_FILE }));
|
|
724
1004
|
}
|
|
725
1005
|
if (process.env.MCP_TS_STORAGE_SQLITE_PATH) {
|
|
726
|
-
console.log(`[Storage] Auto-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
1006
|
+
console.log(`[mcp-ts][Storage] Auto-detection: "sqlite" (${process.env.MCP_TS_STORAGE_SQLITE_PATH})`);
|
|
1007
|
+
return await initializeStorage(new SqliteStorage({ path: process.env.MCP_TS_STORAGE_SQLITE_PATH }));
|
|
1008
|
+
}
|
|
1009
|
+
if (process.env.SUPABASE_URL && (process.env.SUPABASE_SERVICE_ROLE_KEY || process.env.SUPABASE_ANON_KEY)) {
|
|
1010
|
+
try {
|
|
1011
|
+
const { createClient } = await import('@supabase/supabase-js');
|
|
1012
|
+
const url = process.env.SUPABASE_URL;
|
|
1013
|
+
const key = process.env.SUPABASE_SERVICE_ROLE_KEY || process.env.SUPABASE_ANON_KEY;
|
|
1014
|
+
if (!process.env.SUPABASE_SERVICE_ROLE_KEY) {
|
|
1015
|
+
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.');
|
|
1016
|
+
}
|
|
1017
|
+
const client = createClient(url, key);
|
|
1018
|
+
console.log('[mcp-ts][Storage] Auto-detection: "supabase" (via SUPABASE_URL)');
|
|
1019
|
+
return await initializeStorage(new SupabaseStorageBackend(client));
|
|
1020
|
+
} catch (error) {
|
|
1021
|
+
console.error("[mcp-ts][Storage] Supabase auto-detection failed:", error.message);
|
|
1022
|
+
}
|
|
730
1023
|
}
|
|
731
|
-
console.log(
|
|
732
|
-
return new MemoryStorageBackend();
|
|
1024
|
+
console.log('[mcp-ts][Storage] Defaulting to: "memory"');
|
|
1025
|
+
return await initializeStorage(new MemoryStorageBackend());
|
|
733
1026
|
}
|
|
734
1027
|
async function getStorage() {
|
|
735
1028
|
if (storageInstance) {
|
|
736
1029
|
return storageInstance;
|
|
737
1030
|
}
|
|
738
1031
|
if (!storagePromise) {
|
|
739
|
-
storagePromise = createStorage()
|
|
1032
|
+
storagePromise = createStorage().catch((error) => {
|
|
1033
|
+
storagePromise = null;
|
|
1034
|
+
throw error;
|
|
1035
|
+
});
|
|
740
1036
|
}
|
|
741
1037
|
storageInstance = await storagePromise;
|
|
742
1038
|
return storageInstance;
|
|
@@ -757,43 +1053,49 @@ var storage = new Proxy({}, {
|
|
|
757
1053
|
// src/server/mcp/storage-oauth-provider.ts
|
|
758
1054
|
var StorageOAuthClientProvider = class {
|
|
759
1055
|
/**
|
|
760
|
-
* Creates a new
|
|
761
|
-
* @param
|
|
762
|
-
* @param serverId - Server identifier (for tracking which server this OAuth session belongs to)
|
|
763
|
-
* @param sessionId - Session identifier (used as OAuth state)
|
|
764
|
-
* @param clientName - OAuth client name
|
|
765
|
-
* @param baseRedirectUrl - OAuth callback URL
|
|
766
|
-
* @param onRedirect - Optional callback when redirect to authorization is needed
|
|
1056
|
+
* Creates a new storage-backed OAuth provider
|
|
1057
|
+
* @param options - Provider configuration
|
|
767
1058
|
*/
|
|
768
|
-
constructor(
|
|
769
|
-
this
|
|
770
|
-
this
|
|
771
|
-
this
|
|
772
|
-
this
|
|
773
|
-
this
|
|
1059
|
+
constructor(options) {
|
|
1060
|
+
__publicField(this, "identity");
|
|
1061
|
+
__publicField(this, "serverId");
|
|
1062
|
+
__publicField(this, "sessionId");
|
|
1063
|
+
__publicField(this, "redirectUrl");
|
|
1064
|
+
__publicField(this, "clientName");
|
|
1065
|
+
__publicField(this, "clientUri");
|
|
1066
|
+
__publicField(this, "logoUri");
|
|
1067
|
+
__publicField(this, "policyUri");
|
|
1068
|
+
__publicField(this, "clientSecret");
|
|
774
1069
|
__publicField(this, "_authUrl");
|
|
775
1070
|
__publicField(this, "_clientId");
|
|
776
1071
|
__publicField(this, "onRedirectCallback");
|
|
777
1072
|
__publicField(this, "tokenExpiresAt");
|
|
778
|
-
this.
|
|
1073
|
+
this.identity = options.identity;
|
|
1074
|
+
this.serverId = options.serverId;
|
|
1075
|
+
this.sessionId = options.sessionId;
|
|
1076
|
+
this.redirectUrl = options.redirectUrl;
|
|
1077
|
+
this.clientName = options.clientName;
|
|
1078
|
+
this.clientUri = options.clientUri;
|
|
1079
|
+
this.logoUri = options.logoUri;
|
|
1080
|
+
this.policyUri = options.policyUri;
|
|
1081
|
+
this._clientId = options.clientId;
|
|
1082
|
+
this.clientSecret = options.clientSecret;
|
|
1083
|
+
this.onRedirectCallback = options.onRedirect;
|
|
779
1084
|
}
|
|
780
1085
|
get clientMetadata() {
|
|
781
1086
|
return {
|
|
782
|
-
client_name: this.clientName,
|
|
783
|
-
client_uri: this.clientUri,
|
|
1087
|
+
client_name: this.clientName || DEFAULT_CLIENT_NAME,
|
|
1088
|
+
client_uri: this.clientUri || DEFAULT_CLIENT_URI,
|
|
1089
|
+
logo_uri: this.logoUri || DEFAULT_LOGO_URI,
|
|
1090
|
+
policy_uri: this.policyUri || DEFAULT_POLICY_URI,
|
|
784
1091
|
grant_types: ["authorization_code", "refresh_token"],
|
|
785
1092
|
redirect_uris: [this.redirectUrl],
|
|
786
1093
|
response_types: ["code"],
|
|
787
|
-
token_endpoint_auth_method: "none",
|
|
788
|
-
|
|
1094
|
+
token_endpoint_auth_method: this.clientSecret ? "client_secret_basic" : "none",
|
|
1095
|
+
software_id: SOFTWARE_ID,
|
|
1096
|
+
software_version: SOFTWARE_VERSION
|
|
789
1097
|
};
|
|
790
1098
|
}
|
|
791
|
-
get clientUri() {
|
|
792
|
-
return new URL(this.redirectUrl).origin;
|
|
793
|
-
}
|
|
794
|
-
get redirectUrl() {
|
|
795
|
-
return this.baseRedirectUrl;
|
|
796
|
-
}
|
|
797
1099
|
get clientId() {
|
|
798
1100
|
return this._clientId;
|
|
799
1101
|
}
|
|
@@ -828,7 +1130,16 @@ var StorageOAuthClientProvider = class {
|
|
|
828
1130
|
if (data.clientId && !this._clientId) {
|
|
829
1131
|
this._clientId = data.clientId;
|
|
830
1132
|
}
|
|
831
|
-
|
|
1133
|
+
if (data.clientInformation) {
|
|
1134
|
+
return data.clientInformation;
|
|
1135
|
+
}
|
|
1136
|
+
if (!this._clientId) {
|
|
1137
|
+
return void 0;
|
|
1138
|
+
}
|
|
1139
|
+
return {
|
|
1140
|
+
client_id: this._clientId,
|
|
1141
|
+
...this.clientSecret ? { client_secret: this.clientSecret } : {}
|
|
1142
|
+
};
|
|
832
1143
|
}
|
|
833
1144
|
/**
|
|
834
1145
|
* Stores OAuth client information
|
|
@@ -856,14 +1167,14 @@ var StorageOAuthClientProvider = class {
|
|
|
856
1167
|
async state() {
|
|
857
1168
|
return this.sessionId;
|
|
858
1169
|
}
|
|
859
|
-
async checkState(
|
|
1170
|
+
async checkState(_state) {
|
|
860
1171
|
const data = await storage.getSession(this.identity, this.sessionId);
|
|
861
1172
|
if (!data) {
|
|
862
1173
|
return { valid: false, error: "Session not found" };
|
|
863
1174
|
}
|
|
864
1175
|
return { valid: true, serverId: this.serverId };
|
|
865
1176
|
}
|
|
866
|
-
async consumeState(
|
|
1177
|
+
async consumeState(_state) {
|
|
867
1178
|
}
|
|
868
1179
|
async redirectToAuthorization(authUrl) {
|
|
869
1180
|
this._authUrl = authUrl.toString();
|
|
@@ -875,7 +1186,6 @@ var StorageOAuthClientProvider = class {
|
|
|
875
1186
|
if (scope === "all") {
|
|
876
1187
|
await storage.removeSession(this.identity, this.sessionId);
|
|
877
1188
|
} else {
|
|
878
|
-
await this.getSessionData();
|
|
879
1189
|
const updates = {};
|
|
880
1190
|
if (scope === "client") {
|
|
881
1191
|
updates.clientInformation = void 0;
|
|
@@ -923,6 +1233,7 @@ var StorageOAuthClientProvider = class {
|
|
|
923
1233
|
};
|
|
924
1234
|
|
|
925
1235
|
// src/shared/utils.ts
|
|
1236
|
+
init_cjs_shims();
|
|
926
1237
|
function sanitizeServerLabel(name) {
|
|
927
1238
|
let sanitized = name.replace(/[^a-zA-Z0-9-_]/g, "_").replace(/_{2,}/g, "_").toLowerCase();
|
|
928
1239
|
if (!/^[a-zA-Z]/.test(sanitized)) {
|
|
@@ -932,6 +1243,7 @@ function sanitizeServerLabel(name) {
|
|
|
932
1243
|
}
|
|
933
1244
|
|
|
934
1245
|
// src/shared/events.ts
|
|
1246
|
+
init_cjs_shims();
|
|
935
1247
|
var Emitter = class {
|
|
936
1248
|
constructor() {
|
|
937
1249
|
__publicField(this, "listeners", /* @__PURE__ */ new Set());
|
|
@@ -979,6 +1291,7 @@ var Emitter = class {
|
|
|
979
1291
|
};
|
|
980
1292
|
|
|
981
1293
|
// src/shared/errors.ts
|
|
1294
|
+
init_cjs_shims();
|
|
982
1295
|
var McpError = class extends Error {
|
|
983
1296
|
constructor(code, message, cause) {
|
|
984
1297
|
super(message);
|
|
@@ -1195,41 +1508,33 @@ var MCPClient = class _MCPClient {
|
|
|
1195
1508
|
if (!this.serverUrl || !this.callbackUrl || !this.serverId) {
|
|
1196
1509
|
throw new Error("Missing required connection metadata");
|
|
1197
1510
|
}
|
|
1198
|
-
const clientMetadata = {
|
|
1199
|
-
client_name: this.clientName || "MCP Assistant",
|
|
1200
|
-
redirect_uris: [this.callbackUrl],
|
|
1201
|
-
token_endpoint_auth_method: this.clientSecret ? "client_secret_basic" : "none",
|
|
1202
|
-
client_uri: this.clientUri || "https://mcp-assistant.in",
|
|
1203
|
-
logo_uri: this.logoUri || "https://mcp-assistant.in/logo.png",
|
|
1204
|
-
policy_uri: this.policyUri || "https://mcp-assistant.in/privacy",
|
|
1205
|
-
...this.clientId ? { client_id: this.clientId } : {},
|
|
1206
|
-
...this.clientSecret ? { client_secret: this.clientSecret } : {}
|
|
1207
|
-
};
|
|
1208
1511
|
if (!this.oauthProvider) {
|
|
1209
1512
|
if (!this.serverId) {
|
|
1210
1513
|
throw new Error("serverId required for OAuth provider initialization");
|
|
1211
1514
|
}
|
|
1212
|
-
this.oauthProvider = new StorageOAuthClientProvider(
|
|
1213
|
-
this.identity,
|
|
1214
|
-
this.serverId,
|
|
1215
|
-
this.sessionId,
|
|
1216
|
-
|
|
1217
|
-
this.
|
|
1218
|
-
|
|
1515
|
+
this.oauthProvider = new StorageOAuthClientProvider({
|
|
1516
|
+
identity: this.identity,
|
|
1517
|
+
serverId: this.serverId,
|
|
1518
|
+
sessionId: this.sessionId,
|
|
1519
|
+
redirectUrl: this.callbackUrl,
|
|
1520
|
+
clientName: this.clientName,
|
|
1521
|
+
clientUri: this.clientUri,
|
|
1522
|
+
logoUri: this.logoUri,
|
|
1523
|
+
policyUri: this.policyUri,
|
|
1524
|
+
clientId: this.clientId,
|
|
1525
|
+
clientSecret: this.clientSecret,
|
|
1526
|
+
onRedirect: (redirectUrl) => {
|
|
1219
1527
|
if (this.onRedirect) {
|
|
1220
1528
|
this.onRedirect(redirectUrl);
|
|
1221
1529
|
}
|
|
1222
1530
|
}
|
|
1223
|
-
);
|
|
1224
|
-
if (this.clientId && this.oauthProvider) {
|
|
1225
|
-
this.oauthProvider.clientId = this.clientId;
|
|
1226
|
-
}
|
|
1531
|
+
});
|
|
1227
1532
|
}
|
|
1228
1533
|
if (!this.client) {
|
|
1229
1534
|
this.client = new index_js.Client(
|
|
1230
1535
|
{
|
|
1231
|
-
name:
|
|
1232
|
-
version:
|
|
1536
|
+
name: MCP_CLIENT_NAME,
|
|
1537
|
+
version: MCP_CLIENT_VERSION
|
|
1233
1538
|
},
|
|
1234
1539
|
{
|
|
1235
1540
|
capabilities: {
|
|
@@ -1424,8 +1729,8 @@ var MCPClient = class _MCPClient {
|
|
|
1424
1729
|
this.emitProgress("Creating authenticated client...");
|
|
1425
1730
|
this.client = new index_js.Client(
|
|
1426
1731
|
{
|
|
1427
|
-
name:
|
|
1428
|
-
version:
|
|
1732
|
+
name: MCP_CLIENT_NAME,
|
|
1733
|
+
version: MCP_CLIENT_VERSION
|
|
1429
1734
|
},
|
|
1430
1735
|
{
|
|
1431
1736
|
capabilities: {
|
|
@@ -1720,8 +2025,8 @@ var MCPClient = class _MCPClient {
|
|
|
1720
2025
|
}
|
|
1721
2026
|
this.client = new index_js.Client(
|
|
1722
2027
|
{
|
|
1723
|
-
name:
|
|
1724
|
-
version:
|
|
2028
|
+
name: MCP_CLIENT_NAME,
|
|
2029
|
+
version: MCP_CLIENT_VERSION
|
|
1725
2030
|
},
|
|
1726
2031
|
{ capabilities: {} }
|
|
1727
2032
|
);
|
|
@@ -1901,6 +2206,7 @@ var MCPClient = class _MCPClient {
|
|
|
1901
2206
|
};
|
|
1902
2207
|
|
|
1903
2208
|
// src/server/mcp/multi-session-client.ts
|
|
2209
|
+
init_cjs_shims();
|
|
1904
2210
|
var MultiSessionClient = class {
|
|
1905
2211
|
constructor(identity, options = {}) {
|
|
1906
2212
|
__publicField(this, "clients", []);
|
|
@@ -1990,6 +2296,31 @@ var MultiSessionClient = class {
|
|
|
1990
2296
|
}
|
|
1991
2297
|
};
|
|
1992
2298
|
|
|
2299
|
+
// src/server/handlers/sse-handler.ts
|
|
2300
|
+
init_cjs_shims();
|
|
2301
|
+
|
|
2302
|
+
// src/shared/event-routing.ts
|
|
2303
|
+
init_cjs_shims();
|
|
2304
|
+
function isRpcResponseEvent(event) {
|
|
2305
|
+
return "id" in event && ("result" in event || "error" in event);
|
|
2306
|
+
}
|
|
2307
|
+
function isConnectionEvent(event) {
|
|
2308
|
+
if (!("type" in event)) {
|
|
2309
|
+
return false;
|
|
2310
|
+
}
|
|
2311
|
+
switch (event.type) {
|
|
2312
|
+
case "state_changed":
|
|
2313
|
+
case "tools_discovered":
|
|
2314
|
+
case "auth_required":
|
|
2315
|
+
case "error":
|
|
2316
|
+
case "disconnected":
|
|
2317
|
+
case "progress":
|
|
2318
|
+
return true;
|
|
2319
|
+
default:
|
|
2320
|
+
return false;
|
|
2321
|
+
}
|
|
2322
|
+
}
|
|
2323
|
+
|
|
1993
2324
|
// src/server/handlers/sse-handler.ts
|
|
1994
2325
|
var DEFAULT_HEARTBEAT_INTERVAL = 3e4;
|
|
1995
2326
|
var SSEConnectionManager = class {
|
|
@@ -2132,16 +2463,6 @@ var SSEConnectionManager = class {
|
|
|
2132
2463
|
throw new Error(`Connection already exists for server: ${duplicate.serverUrl || duplicate.serverId} (${duplicate.serverName})`);
|
|
2133
2464
|
}
|
|
2134
2465
|
const sessionId = await storage.generateSessionId();
|
|
2135
|
-
this.emitConnectionEvent({
|
|
2136
|
-
type: "state_changed",
|
|
2137
|
-
sessionId,
|
|
2138
|
-
serverId,
|
|
2139
|
-
serverName,
|
|
2140
|
-
serverUrl,
|
|
2141
|
-
state: "CONNECTING",
|
|
2142
|
-
previousState: "DISCONNECTED",
|
|
2143
|
-
timestamp: Date.now()
|
|
2144
|
-
});
|
|
2145
2466
|
try {
|
|
2146
2467
|
const clientMetadata = await this.getResolvedClientMetadata();
|
|
2147
2468
|
const client = new MCPClient({
|
|
@@ -2152,17 +2473,8 @@ var SSEConnectionManager = class {
|
|
|
2152
2473
|
serverUrl,
|
|
2153
2474
|
callbackUrl,
|
|
2154
2475
|
transportType,
|
|
2155
|
-
...clientMetadata
|
|
2476
|
+
...clientMetadata
|
|
2156
2477
|
// Spread client metadata (clientName, clientUri, logoUri, policyUri)
|
|
2157
|
-
onRedirect: (authUrl) => {
|
|
2158
|
-
this.emitConnectionEvent({
|
|
2159
|
-
type: "auth_required",
|
|
2160
|
-
sessionId,
|
|
2161
|
-
serverId,
|
|
2162
|
-
authUrl,
|
|
2163
|
-
timestamp: Date.now()
|
|
2164
|
-
});
|
|
2165
|
-
}
|
|
2166
2478
|
});
|
|
2167
2479
|
this.clients.set(sessionId, client);
|
|
2168
2480
|
client.onConnectionEvent((event) => {
|
|
@@ -2172,20 +2484,19 @@ var SSEConnectionManager = class {
|
|
|
2172
2484
|
this.sendEvent(event);
|
|
2173
2485
|
});
|
|
2174
2486
|
await client.connect();
|
|
2175
|
-
|
|
2176
|
-
this.emitConnectionEvent({
|
|
2177
|
-
type: "tools_discovered",
|
|
2178
|
-
sessionId,
|
|
2179
|
-
serverId,
|
|
2180
|
-
toolCount: tools.tools.length,
|
|
2181
|
-
tools: tools.tools,
|
|
2182
|
-
timestamp: Date.now()
|
|
2183
|
-
});
|
|
2487
|
+
await client.listTools();
|
|
2184
2488
|
return {
|
|
2185
2489
|
sessionId,
|
|
2186
2490
|
success: true
|
|
2187
2491
|
};
|
|
2188
2492
|
} catch (error) {
|
|
2493
|
+
if (error instanceof UnauthorizedError) {
|
|
2494
|
+
this.clients.delete(sessionId);
|
|
2495
|
+
return {
|
|
2496
|
+
sessionId,
|
|
2497
|
+
success: true
|
|
2498
|
+
};
|
|
2499
|
+
}
|
|
2189
2500
|
this.emitConnectionEvent({
|
|
2190
2501
|
type: "error",
|
|
2191
2502
|
sessionId,
|
|
@@ -2287,14 +2598,6 @@ var SSEConnectionManager = class {
|
|
|
2287
2598
|
await client.connect();
|
|
2288
2599
|
this.clients.set(sessionId, client);
|
|
2289
2600
|
const tools = await client.listTools();
|
|
2290
|
-
this.emitConnectionEvent({
|
|
2291
|
-
type: "tools_discovered",
|
|
2292
|
-
sessionId,
|
|
2293
|
-
serverId: session.serverId ?? "unknown",
|
|
2294
|
-
toolCount: tools.tools.length,
|
|
2295
|
-
tools: tools.tools,
|
|
2296
|
-
timestamp: Date.now()
|
|
2297
|
-
});
|
|
2298
2601
|
return { success: true, toolCount: tools.tools.length };
|
|
2299
2602
|
} catch (error) {
|
|
2300
2603
|
this.emitConnectionEvent({
|
|
@@ -2317,16 +2620,6 @@ var SSEConnectionManager = class {
|
|
|
2317
2620
|
if (!session) {
|
|
2318
2621
|
throw new Error("Session not found");
|
|
2319
2622
|
}
|
|
2320
|
-
this.emitConnectionEvent({
|
|
2321
|
-
type: "state_changed",
|
|
2322
|
-
sessionId,
|
|
2323
|
-
serverId: session.serverId ?? "unknown",
|
|
2324
|
-
serverName: session.serverName ?? "Unknown",
|
|
2325
|
-
serverUrl: session.serverUrl,
|
|
2326
|
-
state: "AUTHENTICATING",
|
|
2327
|
-
previousState: "DISCONNECTED",
|
|
2328
|
-
timestamp: Date.now()
|
|
2329
|
-
});
|
|
2330
2623
|
try {
|
|
2331
2624
|
const client = new MCPClient({
|
|
2332
2625
|
identity: this.identity,
|
|
@@ -2336,14 +2629,6 @@ var SSEConnectionManager = class {
|
|
|
2336
2629
|
await client.finishAuth(code);
|
|
2337
2630
|
this.clients.set(sessionId, client);
|
|
2338
2631
|
const tools = await client.listTools();
|
|
2339
|
-
this.emitConnectionEvent({
|
|
2340
|
-
type: "tools_discovered",
|
|
2341
|
-
sessionId,
|
|
2342
|
-
serverId: session.serverId ?? "unknown",
|
|
2343
|
-
toolCount: tools.tools.length,
|
|
2344
|
-
tools: tools.tools,
|
|
2345
|
-
timestamp: Date.now()
|
|
2346
|
-
});
|
|
2347
2632
|
return { success: true, toolCount: tools.tools.length };
|
|
2348
2633
|
} catch (error) {
|
|
2349
2634
|
this.emitConnectionEvent({
|
|
@@ -2421,9 +2706,9 @@ function createSSEHandler(options) {
|
|
|
2421
2706
|
});
|
|
2422
2707
|
writeSSEEvent(res, "connected", { timestamp: Date.now() });
|
|
2423
2708
|
const manager = new SSEConnectionManager(options, (event) => {
|
|
2424
|
-
if (
|
|
2709
|
+
if (isRpcResponseEvent(event)) {
|
|
2425
2710
|
writeSSEEvent(res, "rpc-response", event);
|
|
2426
|
-
} else if (
|
|
2711
|
+
} else if (isConnectionEvent(event)) {
|
|
2427
2712
|
writeSSEEvent(res, "connection", event);
|
|
2428
2713
|
} else {
|
|
2429
2714
|
writeSSEEvent(res, "observability", event);
|
|
@@ -2454,9 +2739,7 @@ function writeSSEEvent(res, event, data) {
|
|
|
2454
2739
|
}
|
|
2455
2740
|
|
|
2456
2741
|
// src/server/handlers/nextjs-handler.ts
|
|
2457
|
-
|
|
2458
|
-
return "id" in event && ("result" in event || "error" in event);
|
|
2459
|
-
}
|
|
2742
|
+
init_cjs_shims();
|
|
2460
2743
|
function createNextMcpHandler(options = {}) {
|
|
2461
2744
|
const {
|
|
2462
2745
|
getIdentity = (request) => new URL(request.url).searchParams.get("identity"),
|
|
@@ -2547,7 +2830,7 @@ data: ${JSON.stringify(data)}
|
|
|
2547
2830
|
(event) => {
|
|
2548
2831
|
if (isRpcResponseEvent(event)) {
|
|
2549
2832
|
sendSSE("rpc-response", event);
|
|
2550
|
-
} else if (
|
|
2833
|
+
} else if (isConnectionEvent(event)) {
|
|
2551
2834
|
sendSSE("connection", event);
|
|
2552
2835
|
} else {
|
|
2553
2836
|
sendSSE("observability", event);
|