@mcp-ts/sdk 1.3.5 → 1.3.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/agui-adapter.d.mts +1 -1
- package/dist/adapters/agui-adapter.d.ts +1 -1
- package/dist/adapters/agui-adapter.js +2 -2
- package/dist/adapters/agui-adapter.js.map +1 -1
- package/dist/adapters/agui-adapter.mjs +2 -2
- package/dist/adapters/agui-adapter.mjs.map +1 -1
- package/dist/adapters/agui-middleware.d.mts +1 -1
- package/dist/adapters/agui-middleware.d.ts +1 -1
- package/dist/adapters/agui-middleware.js.map +1 -1
- package/dist/adapters/agui-middleware.mjs.map +1 -1
- package/dist/adapters/ai-adapter.d.mts +1 -1
- package/dist/adapters/ai-adapter.d.ts +1 -1
- package/dist/adapters/ai-adapter.js +1 -1
- package/dist/adapters/ai-adapter.js.map +1 -1
- package/dist/adapters/ai-adapter.mjs +1 -1
- package/dist/adapters/ai-adapter.mjs.map +1 -1
- package/dist/adapters/langchain-adapter.d.mts +1 -1
- package/dist/adapters/langchain-adapter.d.ts +1 -1
- package/dist/adapters/langchain-adapter.js +1 -1
- package/dist/adapters/langchain-adapter.js.map +1 -1
- package/dist/adapters/langchain-adapter.mjs +1 -1
- package/dist/adapters/langchain-adapter.mjs.map +1 -1
- package/dist/adapters/mastra-adapter.d.mts +1 -1
- package/dist/adapters/mastra-adapter.d.ts +1 -1
- package/dist/adapters/mastra-adapter.js +1 -1
- package/dist/adapters/mastra-adapter.js.map +1 -1
- package/dist/adapters/mastra-adapter.mjs +1 -1
- package/dist/adapters/mastra-adapter.mjs.map +1 -1
- package/dist/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/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +411 -90
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +350 -91
- package/dist/index.mjs.map +1 -1
- package/dist/{multi-session-client-BYLarghq.d.ts → multi-session-client-CHE8QpVE.d.ts} +75 -5
- package/dist/{multi-session-client-CzhMkE0k.d.mts → multi-session-client-CQsRbxYI.d.mts} +75 -5
- package/dist/server/index.d.mts +1 -1
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.js +394 -90
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +350 -91
- package/dist/server/index.mjs.map +1 -1
- package/dist/shared/index.js +10 -2
- package/dist/shared/index.js.map +1 -1
- package/dist/shared/index.mjs +10 -2
- package/dist/shared/index.mjs.map +1 -1
- package/package.json +19 -6
- package/src/adapters/agui-adapter.ts +222 -222
- package/src/adapters/ai-adapter.ts +115 -115
- package/src/adapters/langchain-adapter.ts +127 -127
- package/src/adapters/mastra-adapter.ts +126 -126
- package/src/bin/mcp-ts.ts +102 -0
- package/src/server/handlers/nextjs-handler.ts +12 -12
- package/src/server/handlers/sse-handler.ts +61 -61
- package/src/server/mcp/multi-session-client.ts +135 -39
- package/src/server/storage/file-backend.ts +4 -16
- package/src/server/storage/index.ts +68 -25
- package/src/server/storage/memory-backend.ts +7 -16
- package/src/server/storage/redis-backend.ts +12 -16
- package/src/server/storage/sqlite-backend.ts +3 -6
- package/src/server/storage/supabase-backend.ts +228 -0
- package/src/shared/event-routing.ts +28 -28
- package/src/shared/utils.ts +22 -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;
|
|
@@ -149,7 +175,8 @@ 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
|
|
|
152
|
-
// src/
|
|
178
|
+
// src/shared/utils.ts
|
|
179
|
+
init_cjs_shims();
|
|
153
180
|
var firstChar = nanoid.customAlphabet(
|
|
154
181
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
|
|
155
182
|
1
|
|
@@ -158,6 +185,18 @@ var rest = nanoid.customAlphabet(
|
|
|
158
185
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
|
|
159
186
|
11
|
|
160
187
|
);
|
|
188
|
+
function sanitizeServerLabel(name) {
|
|
189
|
+
let sanitized = name.replace(/[^a-zA-Z0-9-_]/g, "_").replace(/_{2,}/g, "_").toLowerCase();
|
|
190
|
+
if (!/^[a-zA-Z]/.test(sanitized)) {
|
|
191
|
+
sanitized = "s_" + sanitized;
|
|
192
|
+
}
|
|
193
|
+
return sanitized;
|
|
194
|
+
}
|
|
195
|
+
function generateSessionId() {
|
|
196
|
+
return firstChar() + rest();
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// src/server/storage/redis-backend.ts
|
|
161
200
|
var RedisStorageBackend = class {
|
|
162
201
|
constructor(redis2) {
|
|
163
202
|
this.redis = redis2;
|
|
@@ -166,6 +205,14 @@ var RedisStorageBackend = class {
|
|
|
166
205
|
__publicField(this, "IDENTITY_KEY_PREFIX", "mcp:identity:");
|
|
167
206
|
__publicField(this, "IDENTITY_KEY_SUFFIX", ":sessions");
|
|
168
207
|
}
|
|
208
|
+
async init() {
|
|
209
|
+
try {
|
|
210
|
+
await this.redis.ping();
|
|
211
|
+
console.log("[mcp-ts][Storage] Redis: \u2713 Connected to server.");
|
|
212
|
+
} catch (error) {
|
|
213
|
+
throw new Error(`[RedisStorage] Failed to connect to Redis: ${error.message}`);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
169
216
|
/**
|
|
170
217
|
* Generates Redis key for a specific session
|
|
171
218
|
* @private
|
|
@@ -208,7 +255,7 @@ var RedisStorageBackend = class {
|
|
|
208
255
|
return Array.from(keys);
|
|
209
256
|
}
|
|
210
257
|
generateSessionId() {
|
|
211
|
-
return
|
|
258
|
+
return generateSessionId();
|
|
212
259
|
}
|
|
213
260
|
async createSession(session, ttl) {
|
|
214
261
|
const { sessionId, identity } = session;
|
|
@@ -376,14 +423,9 @@ var RedisStorageBackend = class {
|
|
|
376
423
|
}
|
|
377
424
|
}
|
|
378
425
|
};
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
);
|
|
383
|
-
var rest2 = nanoid.customAlphabet(
|
|
384
|
-
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
|
|
385
|
-
11
|
|
386
|
-
);
|
|
426
|
+
|
|
427
|
+
// src/server/storage/memory-backend.ts
|
|
428
|
+
init_cjs_shims();
|
|
387
429
|
var MemoryStorageBackend = class {
|
|
388
430
|
constructor() {
|
|
389
431
|
// Map<identity:sessionId, SessionData>
|
|
@@ -391,11 +433,14 @@ var MemoryStorageBackend = class {
|
|
|
391
433
|
// Map<identity, Set<sessionId>>
|
|
392
434
|
__publicField(this, "identitySessions", /* @__PURE__ */ new Map());
|
|
393
435
|
}
|
|
436
|
+
async init() {
|
|
437
|
+
console.log("[mcp-ts][Storage] Memory: \u2713 internal memory store active.");
|
|
438
|
+
}
|
|
394
439
|
getSessionKey(identity, sessionId) {
|
|
395
440
|
return `${identity}:${sessionId}`;
|
|
396
441
|
}
|
|
397
442
|
generateSessionId() {
|
|
398
|
-
return
|
|
443
|
+
return generateSessionId();
|
|
399
444
|
}
|
|
400
445
|
async createSession(session, ttl) {
|
|
401
446
|
const { sessionId, identity } = session;
|
|
@@ -466,14 +511,9 @@ var MemoryStorageBackend = class {
|
|
|
466
511
|
async disconnect() {
|
|
467
512
|
}
|
|
468
513
|
};
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
);
|
|
473
|
-
var rest3 = nanoid.customAlphabet(
|
|
474
|
-
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
|
|
475
|
-
11
|
|
476
|
-
);
|
|
514
|
+
|
|
515
|
+
// src/server/storage/file-backend.ts
|
|
516
|
+
init_cjs_shims();
|
|
477
517
|
var FileStorageBackend = class {
|
|
478
518
|
/**
|
|
479
519
|
* @param options.path Path to the JSON file storage (default: ./sessions.json)
|
|
@@ -510,6 +550,7 @@ var FileStorageBackend = class {
|
|
|
510
550
|
}
|
|
511
551
|
}
|
|
512
552
|
this.initialized = true;
|
|
553
|
+
console.log(`[mcp-ts][Storage] File: \u2713 storage directory at ${path__namespace.dirname(this.filePath)} verified.`);
|
|
513
554
|
}
|
|
514
555
|
async ensureInitialized() {
|
|
515
556
|
if (!this.initialized) await this.init();
|
|
@@ -523,7 +564,7 @@ var FileStorageBackend = class {
|
|
|
523
564
|
return `${identity}:${sessionId}`;
|
|
524
565
|
}
|
|
525
566
|
generateSessionId() {
|
|
526
|
-
return
|
|
567
|
+
return generateSessionId();
|
|
527
568
|
}
|
|
528
569
|
async createSession(session, ttl) {
|
|
529
570
|
await this.ensureInitialized();
|
|
@@ -586,6 +627,9 @@ var FileStorageBackend = class {
|
|
|
586
627
|
async disconnect() {
|
|
587
628
|
}
|
|
588
629
|
};
|
|
630
|
+
|
|
631
|
+
// src/server/storage/sqlite-backend.ts
|
|
632
|
+
init_cjs_shims();
|
|
589
633
|
var SqliteStorage = class {
|
|
590
634
|
constructor(options = {}) {
|
|
591
635
|
__publicField(this, "db", null);
|
|
@@ -614,6 +658,7 @@ var SqliteStorage = class {
|
|
|
614
658
|
CREATE INDEX IF NOT EXISTS idx_${this.table}_identity ON ${this.table}(identity);
|
|
615
659
|
`);
|
|
616
660
|
this.initialized = true;
|
|
661
|
+
console.log(`[mcp-ts][Storage] SQLite: \u2713 database at ${this.dbPath} verified.`);
|
|
617
662
|
} catch (error) {
|
|
618
663
|
if (error.code === "MODULE_NOT_FOUND" || error.message?.includes("better-sqlite3")) {
|
|
619
664
|
throw new Error(
|
|
@@ -629,12 +674,7 @@ var SqliteStorage = class {
|
|
|
629
674
|
}
|
|
630
675
|
}
|
|
631
676
|
generateSessionId() {
|
|
632
|
-
|
|
633
|
-
let result = "";
|
|
634
|
-
for (let i = 0; i < 32; i++) {
|
|
635
|
-
result += chars.charAt(Math.floor(Math.random() * chars.length));
|
|
636
|
-
}
|
|
637
|
-
return result;
|
|
677
|
+
return generateSessionId();
|
|
638
678
|
}
|
|
639
679
|
async createSession(session, ttl) {
|
|
640
680
|
this.ensureInitialized();
|
|
@@ -729,6 +769,161 @@ var SqliteStorage = class {
|
|
|
729
769
|
}
|
|
730
770
|
};
|
|
731
771
|
|
|
772
|
+
// src/server/storage/supabase-backend.ts
|
|
773
|
+
init_cjs_shims();
|
|
774
|
+
var SupabaseStorageBackend = class {
|
|
775
|
+
constructor(supabase) {
|
|
776
|
+
this.supabase = supabase;
|
|
777
|
+
__publicField(this, "DEFAULT_TTL", SESSION_TTL_SECONDS);
|
|
778
|
+
}
|
|
779
|
+
async init() {
|
|
780
|
+
const { error } = await this.supabase.from("mcp_sessions").select("session_id").limit(0);
|
|
781
|
+
if (error) {
|
|
782
|
+
if (error.code === "42P01") {
|
|
783
|
+
throw new Error(
|
|
784
|
+
'[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.'
|
|
785
|
+
);
|
|
786
|
+
}
|
|
787
|
+
throw new Error(`[SupabaseStorage] Initialization check failed: ${error.message}`);
|
|
788
|
+
}
|
|
789
|
+
console.log('[mcp-ts][Storage] Supabase: \u2713 "mcp_sessions" table verified.');
|
|
790
|
+
}
|
|
791
|
+
generateSessionId() {
|
|
792
|
+
return generateSessionId();
|
|
793
|
+
}
|
|
794
|
+
mapRowToSessionData(row) {
|
|
795
|
+
return {
|
|
796
|
+
sessionId: row.session_id,
|
|
797
|
+
serverId: row.server_id,
|
|
798
|
+
serverName: row.server_name,
|
|
799
|
+
serverUrl: row.server_url,
|
|
800
|
+
transportType: row.transport_type,
|
|
801
|
+
callbackUrl: row.callback_url,
|
|
802
|
+
createdAt: new Date(row.created_at).getTime(),
|
|
803
|
+
identity: row.identity,
|
|
804
|
+
headers: row.headers,
|
|
805
|
+
active: row.active,
|
|
806
|
+
clientInformation: row.client_information,
|
|
807
|
+
tokens: row.tokens,
|
|
808
|
+
codeVerifier: row.code_verifier,
|
|
809
|
+
clientId: row.client_id
|
|
810
|
+
};
|
|
811
|
+
}
|
|
812
|
+
async createSession(session, ttl) {
|
|
813
|
+
const { sessionId, identity } = session;
|
|
814
|
+
if (!sessionId || !identity) throw new Error("identity and sessionId required");
|
|
815
|
+
const effectiveTtl = ttl ?? this.DEFAULT_TTL;
|
|
816
|
+
const expiresAt = new Date(Date.now() + effectiveTtl * 1e3).toISOString();
|
|
817
|
+
const { error } = await this.supabase.from("mcp_sessions").insert({
|
|
818
|
+
session_id: sessionId,
|
|
819
|
+
user_id: identity,
|
|
820
|
+
// Maps user_id to identity to support RLS using auth.uid()
|
|
821
|
+
server_id: session.serverId,
|
|
822
|
+
server_name: session.serverName,
|
|
823
|
+
server_url: session.serverUrl,
|
|
824
|
+
transport_type: session.transportType,
|
|
825
|
+
callback_url: session.callbackUrl,
|
|
826
|
+
created_at: new Date(session.createdAt || Date.now()).toISOString(),
|
|
827
|
+
identity,
|
|
828
|
+
headers: session.headers,
|
|
829
|
+
active: session.active ?? false,
|
|
830
|
+
client_information: session.clientInformation,
|
|
831
|
+
tokens: session.tokens,
|
|
832
|
+
code_verifier: session.codeVerifier,
|
|
833
|
+
client_id: session.clientId,
|
|
834
|
+
expires_at: expiresAt
|
|
835
|
+
});
|
|
836
|
+
if (error) {
|
|
837
|
+
if (error.code === "23505") {
|
|
838
|
+
throw new Error(`Session ${sessionId} already exists`);
|
|
839
|
+
}
|
|
840
|
+
throw new Error(`Failed to create session in Supabase: ${error.message}`);
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
async updateSession(identity, sessionId, data, ttl) {
|
|
844
|
+
const effectiveTtl = ttl ?? this.DEFAULT_TTL;
|
|
845
|
+
const expiresAt = new Date(Date.now() + effectiveTtl * 1e3).toISOString();
|
|
846
|
+
const updateData = {
|
|
847
|
+
expires_at: expiresAt,
|
|
848
|
+
updated_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
849
|
+
};
|
|
850
|
+
if ("serverId" in data) updateData.server_id = data.serverId;
|
|
851
|
+
if ("serverName" in data) updateData.server_name = data.serverName;
|
|
852
|
+
if ("serverUrl" in data) updateData.server_url = data.serverUrl;
|
|
853
|
+
if ("transportType" in data) updateData.transport_type = data.transportType;
|
|
854
|
+
if ("callbackUrl" in data) updateData.callback_url = data.callbackUrl;
|
|
855
|
+
if ("active" in data) updateData.active = data.active;
|
|
856
|
+
if ("headers" in data) updateData.headers = data.headers;
|
|
857
|
+
if ("clientInformation" in data) updateData.client_information = data.clientInformation;
|
|
858
|
+
if ("tokens" in data) updateData.tokens = data.tokens;
|
|
859
|
+
if ("codeVerifier" in data) updateData.code_verifier = data.codeVerifier;
|
|
860
|
+
if ("clientId" in data) updateData.client_id = data.clientId;
|
|
861
|
+
const { data: updatedRows, error } = await this.supabase.from("mcp_sessions").update(updateData).eq("identity", identity).eq("session_id", sessionId).select("id");
|
|
862
|
+
if (error) {
|
|
863
|
+
throw new Error(`Failed to update session: ${error.message}`);
|
|
864
|
+
}
|
|
865
|
+
if (!updatedRows || updatedRows.length === 0) {
|
|
866
|
+
throw new Error(`Session ${sessionId} not found for identity ${identity}`);
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
async getSession(identity, sessionId) {
|
|
870
|
+
const { data, error } = await this.supabase.from("mcp_sessions").select("*").eq("identity", identity).eq("session_id", sessionId).maybeSingle();
|
|
871
|
+
if (error) {
|
|
872
|
+
console.error("[SupabaseStorage] Failed to get session:", error);
|
|
873
|
+
return null;
|
|
874
|
+
}
|
|
875
|
+
if (!data) return null;
|
|
876
|
+
return this.mapRowToSessionData(data);
|
|
877
|
+
}
|
|
878
|
+
async getIdentitySessionsData(identity) {
|
|
879
|
+
const { data, error } = await this.supabase.from("mcp_sessions").select("*").eq("identity", identity);
|
|
880
|
+
if (error) {
|
|
881
|
+
console.error(`[SupabaseStorage] Failed to get session data for ${identity}:`, error);
|
|
882
|
+
return [];
|
|
883
|
+
}
|
|
884
|
+
return data.map((row) => this.mapRowToSessionData(row));
|
|
885
|
+
}
|
|
886
|
+
async removeSession(identity, sessionId) {
|
|
887
|
+
const { error } = await this.supabase.from("mcp_sessions").delete().eq("identity", identity).eq("session_id", sessionId);
|
|
888
|
+
if (error) {
|
|
889
|
+
console.error("[SupabaseStorage] Failed to remove session:", error);
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
async getIdentityMcpSessions(identity) {
|
|
893
|
+
const { data, error } = await this.supabase.from("mcp_sessions").select("session_id").eq("identity", identity);
|
|
894
|
+
if (error) {
|
|
895
|
+
console.error(`[SupabaseStorage] Failed to get sessions for ${identity}:`, error);
|
|
896
|
+
return [];
|
|
897
|
+
}
|
|
898
|
+
return data.map((row) => row.session_id);
|
|
899
|
+
}
|
|
900
|
+
async getAllSessionIds() {
|
|
901
|
+
const { data, error } = await this.supabase.from("mcp_sessions").select("session_id");
|
|
902
|
+
if (error) {
|
|
903
|
+
console.error("[SupabaseStorage] Failed to get all sessions:", error);
|
|
904
|
+
return [];
|
|
905
|
+
}
|
|
906
|
+
return data.map((row) => row.session_id);
|
|
907
|
+
}
|
|
908
|
+
async clearAll() {
|
|
909
|
+
const { error } = await this.supabase.from("mcp_sessions").delete().neq("session_id", "");
|
|
910
|
+
if (error) {
|
|
911
|
+
console.error("[SupabaseStorage] Failed to clear sessions:", error);
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
async cleanupExpiredSessions() {
|
|
915
|
+
const { error } = await this.supabase.from("mcp_sessions").delete().lt("expires_at", (/* @__PURE__ */ new Date()).toISOString());
|
|
916
|
+
if (error) {
|
|
917
|
+
console.error("[SupabaseStorage] Failed to cleanup expired sessions:", error);
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
async disconnect() {
|
|
921
|
+
}
|
|
922
|
+
};
|
|
923
|
+
|
|
924
|
+
// src/server/storage/types.ts
|
|
925
|
+
init_cjs_shims();
|
|
926
|
+
|
|
732
927
|
// src/server/storage/index.ts
|
|
733
928
|
var storageInstance = null;
|
|
734
929
|
var storagePromise = null;
|
|
@@ -747,53 +942,85 @@ async function createStorage() {
|
|
|
747
942
|
try {
|
|
748
943
|
const { getRedis: getRedis2 } = await Promise.resolve().then(() => (init_redis(), redis_exports));
|
|
749
944
|
const redis2 = await getRedis2();
|
|
750
|
-
console.log(
|
|
751
|
-
return new RedisStorageBackend(redis2);
|
|
945
|
+
console.log('[mcp-ts][Storage] Explicit selection: "redis"');
|
|
946
|
+
return await initializeStorage(new RedisStorageBackend(redis2));
|
|
752
947
|
} catch (error) {
|
|
753
|
-
console.error("[Storage] Failed to initialize Redis:", error.message);
|
|
754
|
-
console.log("[Storage] Falling back to In-Memory storage");
|
|
755
|
-
return new MemoryStorageBackend();
|
|
948
|
+
console.error("[mcp-ts][Storage] Failed to initialize Redis:", error.message);
|
|
949
|
+
console.log("[mcp-ts][Storage] Falling back to In-Memory storage");
|
|
950
|
+
return await initializeStorage(new MemoryStorageBackend());
|
|
756
951
|
}
|
|
757
952
|
}
|
|
758
953
|
if (type === "file") {
|
|
759
954
|
const filePath = process.env.MCP_TS_STORAGE_FILE;
|
|
760
|
-
|
|
761
|
-
console.warn('[Storage] MCP_TS_STORAGE_TYPE is "file" but MCP_TS_STORAGE_FILE is missing');
|
|
762
|
-
}
|
|
763
|
-
console.log(`[Storage] Using File storage (${filePath}) (Explicit)`);
|
|
955
|
+
console.log(`[mcp-ts][Storage] Explicit selection: "file" (${filePath || "default"})`);
|
|
764
956
|
return await initializeStorage(new FileStorageBackend({ path: filePath }));
|
|
765
957
|
}
|
|
766
958
|
if (type === "sqlite") {
|
|
767
959
|
const dbPath = process.env.MCP_TS_STORAGE_SQLITE_PATH;
|
|
768
|
-
console.log(`[Storage]
|
|
960
|
+
console.log(`[mcp-ts][Storage] Explicit selection: "sqlite" (${dbPath || "default"})`);
|
|
769
961
|
return await initializeStorage(new SqliteStorage({ path: dbPath }));
|
|
770
962
|
}
|
|
963
|
+
if (type === "supabase") {
|
|
964
|
+
const url = process.env.SUPABASE_URL;
|
|
965
|
+
const key = process.env.SUPABASE_SERVICE_ROLE_KEY || process.env.SUPABASE_ANON_KEY;
|
|
966
|
+
if (!url || !key) {
|
|
967
|
+
console.warn('[mcp-ts][Storage] Explicit selection "supabase" requires SUPABASE_URL and SUPABASE_SERVICE_ROLE_KEY.');
|
|
968
|
+
} else {
|
|
969
|
+
if (!process.env.SUPABASE_SERVICE_ROLE_KEY) {
|
|
970
|
+
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.');
|
|
971
|
+
}
|
|
972
|
+
try {
|
|
973
|
+
const { createClient } = await import('@supabase/supabase-js');
|
|
974
|
+
const client = createClient(url, key);
|
|
975
|
+
console.log('[mcp-ts][Storage] Explicit selection: "supabase"');
|
|
976
|
+
return await initializeStorage(new SupabaseStorageBackend(client));
|
|
977
|
+
} catch (error) {
|
|
978
|
+
console.error("[mcp-ts][Storage] Failed to initialize Supabase:", error.message);
|
|
979
|
+
console.log("[mcp-ts][Storage] Falling back to In-Memory storage");
|
|
980
|
+
return await initializeStorage(new MemoryStorageBackend());
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
}
|
|
771
984
|
if (type === "memory") {
|
|
772
|
-
console.log(
|
|
773
|
-
return new MemoryStorageBackend();
|
|
985
|
+
console.log('[mcp-ts][Storage] Explicit selection: "memory"');
|
|
986
|
+
return await initializeStorage(new MemoryStorageBackend());
|
|
774
987
|
}
|
|
775
988
|
if (process.env.REDIS_URL) {
|
|
776
989
|
try {
|
|
777
990
|
const { getRedis: getRedis2 } = await Promise.resolve().then(() => (init_redis(), redis_exports));
|
|
778
991
|
const redis2 = await getRedis2();
|
|
779
|
-
console.log(
|
|
780
|
-
return new RedisStorageBackend(redis2);
|
|
992
|
+
console.log('[mcp-ts][Storage] Auto-detection: "redis" (via REDIS_URL)');
|
|
993
|
+
return await initializeStorage(new RedisStorageBackend(redis2));
|
|
781
994
|
} catch (error) {
|
|
782
|
-
console.error("[Storage] Redis auto-detection failed:", error.message);
|
|
783
|
-
console.log("[Storage] Falling back to
|
|
784
|
-
return new MemoryStorageBackend();
|
|
995
|
+
console.error("[mcp-ts][Storage] Redis auto-detection failed:", error.message);
|
|
996
|
+
console.log("[mcp-ts][Storage] Falling back to next available backend");
|
|
785
997
|
}
|
|
786
998
|
}
|
|
787
999
|
if (process.env.MCP_TS_STORAGE_FILE) {
|
|
788
|
-
console.log(`[Storage] Auto-
|
|
1000
|
+
console.log(`[mcp-ts][Storage] Auto-detection: "file" (${process.env.MCP_TS_STORAGE_FILE})`);
|
|
789
1001
|
return await initializeStorage(new FileStorageBackend({ path: process.env.MCP_TS_STORAGE_FILE }));
|
|
790
1002
|
}
|
|
791
1003
|
if (process.env.MCP_TS_STORAGE_SQLITE_PATH) {
|
|
792
|
-
console.log(`[Storage] Auto-
|
|
1004
|
+
console.log(`[mcp-ts][Storage] Auto-detection: "sqlite" (${process.env.MCP_TS_STORAGE_SQLITE_PATH})`);
|
|
793
1005
|
return await initializeStorage(new SqliteStorage({ path: process.env.MCP_TS_STORAGE_SQLITE_PATH }));
|
|
794
1006
|
}
|
|
795
|
-
|
|
796
|
-
|
|
1007
|
+
if (process.env.SUPABASE_URL && (process.env.SUPABASE_SERVICE_ROLE_KEY || process.env.SUPABASE_ANON_KEY)) {
|
|
1008
|
+
try {
|
|
1009
|
+
const { createClient } = await import('@supabase/supabase-js');
|
|
1010
|
+
const url = process.env.SUPABASE_URL;
|
|
1011
|
+
const key = process.env.SUPABASE_SERVICE_ROLE_KEY || process.env.SUPABASE_ANON_KEY;
|
|
1012
|
+
if (!process.env.SUPABASE_SERVICE_ROLE_KEY) {
|
|
1013
|
+
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.');
|
|
1014
|
+
}
|
|
1015
|
+
const client = createClient(url, key);
|
|
1016
|
+
console.log('[mcp-ts][Storage] Auto-detection: "supabase" (via SUPABASE_URL)');
|
|
1017
|
+
return await initializeStorage(new SupabaseStorageBackend(client));
|
|
1018
|
+
} catch (error) {
|
|
1019
|
+
console.error("[mcp-ts][Storage] Supabase auto-detection failed:", error.message);
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
console.log('[mcp-ts][Storage] Defaulting to: "memory"');
|
|
1023
|
+
return await initializeStorage(new MemoryStorageBackend());
|
|
797
1024
|
}
|
|
798
1025
|
async function getStorage() {
|
|
799
1026
|
if (storageInstance) {
|
|
@@ -1003,16 +1230,8 @@ var StorageOAuthClientProvider = class {
|
|
|
1003
1230
|
}
|
|
1004
1231
|
};
|
|
1005
1232
|
|
|
1006
|
-
// src/shared/utils.ts
|
|
1007
|
-
function sanitizeServerLabel(name) {
|
|
1008
|
-
let sanitized = name.replace(/[^a-zA-Z0-9-_]/g, "_").replace(/_{2,}/g, "_").toLowerCase();
|
|
1009
|
-
if (!/^[a-zA-Z]/.test(sanitized)) {
|
|
1010
|
-
sanitized = "s_" + sanitized;
|
|
1011
|
-
}
|
|
1012
|
-
return sanitized;
|
|
1013
|
-
}
|
|
1014
|
-
|
|
1015
1233
|
// src/shared/events.ts
|
|
1234
|
+
init_cjs_shims();
|
|
1016
1235
|
var Emitter = class {
|
|
1017
1236
|
constructor() {
|
|
1018
1237
|
__publicField(this, "listeners", /* @__PURE__ */ new Set());
|
|
@@ -1074,6 +1293,7 @@ var DisposableStore = class {
|
|
|
1074
1293
|
};
|
|
1075
1294
|
|
|
1076
1295
|
// src/shared/errors.ts
|
|
1296
|
+
init_cjs_shims();
|
|
1077
1297
|
var McpError = class extends Error {
|
|
1078
1298
|
constructor(code, message, cause) {
|
|
1079
1299
|
super(message);
|
|
@@ -2042,47 +2262,133 @@ var MCPClient = class _MCPClient {
|
|
|
2042
2262
|
};
|
|
2043
2263
|
|
|
2044
2264
|
// src/server/mcp/multi-session-client.ts
|
|
2265
|
+
init_cjs_shims();
|
|
2266
|
+
var DEFAULT_TIMEOUT_MS = 15e3;
|
|
2267
|
+
var DEFAULT_MAX_RETRIES = 2;
|
|
2268
|
+
var DEFAULT_RETRY_DELAY_MS = 1e3;
|
|
2269
|
+
var CONNECTION_BATCH_SIZE = 5;
|
|
2045
2270
|
var MultiSessionClient = class {
|
|
2271
|
+
/**
|
|
2272
|
+
* Creates a new MultiSessionClient for the given user identity.
|
|
2273
|
+
*
|
|
2274
|
+
* @param identity - A unique string identifying the user (e.g. user ID or email).
|
|
2275
|
+
* @param options - Optional tuning for connection timeout, retry count, and retry delay.
|
|
2276
|
+
* Falls back to sensible defaults if not provided.
|
|
2277
|
+
*/
|
|
2046
2278
|
constructor(identity, options = {}) {
|
|
2047
2279
|
__publicField(this, "clients", []);
|
|
2048
2280
|
__publicField(this, "identity");
|
|
2049
2281
|
__publicField(this, "options");
|
|
2282
|
+
__publicField(this, "connectionPromises", /* @__PURE__ */ new Map());
|
|
2050
2283
|
this.identity = identity;
|
|
2051
2284
|
this.options = {
|
|
2052
|
-
timeout:
|
|
2053
|
-
maxRetries:
|
|
2054
|
-
retryDelay:
|
|
2285
|
+
timeout: DEFAULT_TIMEOUT_MS,
|
|
2286
|
+
maxRetries: DEFAULT_MAX_RETRIES,
|
|
2287
|
+
retryDelay: DEFAULT_RETRY_DELAY_MS,
|
|
2055
2288
|
...options
|
|
2056
2289
|
};
|
|
2057
2290
|
}
|
|
2291
|
+
/**
|
|
2292
|
+
* Fetches all sessions for this identity from storage and returns only the
|
|
2293
|
+
* ones that are ready to connect.
|
|
2294
|
+
*
|
|
2295
|
+
* A session is considered connectable when:
|
|
2296
|
+
* - It has a `serverId`, `serverUrl`, and `callbackUrl` (i.e. it was fully initialized)
|
|
2297
|
+
* - Its `active` flag is not explicitly `false` — sessions with `active: false` are
|
|
2298
|
+
* either mid-OAuth flow, auth-pending, or previously failed. We skip those here
|
|
2299
|
+
* and let the OAuth flow complete separately before we try to reconnect them.
|
|
2300
|
+
*
|
|
2301
|
+
* Note: Sessions where `active` is `undefined` (legacy records) are included
|
|
2302
|
+
* for backwards compatibility.
|
|
2303
|
+
*/
|
|
2058
2304
|
async getActiveSessions() {
|
|
2059
2305
|
const sessions = await storage.getIdentitySessionsData(this.identity);
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2306
|
+
const valid = sessions.filter(
|
|
2307
|
+
(s) => s.serverId && s.serverUrl && s.callbackUrl && s.active !== false
|
|
2308
|
+
// exclude OAuth-pending / failed sessions
|
|
2063
2309
|
);
|
|
2064
|
-
const valid = sessions.filter((s) => s.serverId && s.serverUrl && s.callbackUrl);
|
|
2065
|
-
console.log(`[MultiSessionClient] Filtered valid sessions:`, valid.length);
|
|
2066
2310
|
return valid;
|
|
2067
2311
|
}
|
|
2312
|
+
/**
|
|
2313
|
+
* Connects to a list of sessions in controlled batches of `CONNECTION_BATCH_SIZE`.
|
|
2314
|
+
*
|
|
2315
|
+
* Batching prevents overwhelming the event loop or external servers when a user
|
|
2316
|
+
* has many active MCP sessions (e.g. 20+ servers). Within each batch, sessions
|
|
2317
|
+
* are connected concurrently using `Promise.all` for speed.
|
|
2318
|
+
*/
|
|
2068
2319
|
async connectInBatches(sessions) {
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
const batch = sessions.slice(i, i + BATCH_SIZE);
|
|
2320
|
+
for (let i = 0; i < sessions.length; i += CONNECTION_BATCH_SIZE) {
|
|
2321
|
+
const batch = sessions.slice(i, i + CONNECTION_BATCH_SIZE);
|
|
2072
2322
|
await Promise.all(batch.map((session) => this.connectSession(session)));
|
|
2073
2323
|
}
|
|
2074
2324
|
}
|
|
2325
|
+
/**
|
|
2326
|
+
* Connects a single session, with built-in deduplication to prevent race conditions.
|
|
2327
|
+
*
|
|
2328
|
+
* - If a client for this session already exists and is connected, returns immediately.
|
|
2329
|
+
* - If a connection attempt for this session is already in-flight (e.g. from a
|
|
2330
|
+
* concurrent call), it joins the existing promise instead of starting a new one.
|
|
2331
|
+
* This is the key concurrency lock — the `connectionPromises` map acts as a
|
|
2332
|
+
* per-session mutex so we never spin up two physical connections for the same session.
|
|
2333
|
+
* - On completion (success or failure), the promise is cleaned up from the map.
|
|
2334
|
+
*/
|
|
2075
2335
|
async connectSession(session) {
|
|
2076
2336
|
const existingClient = this.clients.find((c) => c.getSessionId() === session.sessionId);
|
|
2077
2337
|
if (existingClient?.isConnected()) {
|
|
2078
2338
|
return;
|
|
2079
2339
|
}
|
|
2080
|
-
|
|
2081
|
-
|
|
2340
|
+
if (this.connectionPromises.has(session.sessionId)) {
|
|
2341
|
+
return this.connectionPromises.get(session.sessionId);
|
|
2342
|
+
}
|
|
2343
|
+
const connectPromise = this.establishConnectionWithRetries(session);
|
|
2344
|
+
this.connectionPromises.set(session.sessionId, connectPromise);
|
|
2345
|
+
try {
|
|
2346
|
+
await connectPromise;
|
|
2347
|
+
} finally {
|
|
2348
|
+
this.connectionPromises.delete(session.sessionId);
|
|
2349
|
+
}
|
|
2350
|
+
}
|
|
2351
|
+
/**
|
|
2352
|
+
* The core connection loop for a single session.
|
|
2353
|
+
*
|
|
2354
|
+
* Attempts to establish a physical MCP connection, retrying up to `maxRetries` times
|
|
2355
|
+
* if the connection fails. Each attempt:
|
|
2356
|
+
* 1. Creates a fresh `MCPClient` instance from the session data.
|
|
2357
|
+
* 2. Races the connect call against a timeout promise — if the server doesn't respond
|
|
2358
|
+
* within `timeoutMs`, the attempt is aborted and counted as a failure.
|
|
2359
|
+
* 3. On success, replaces any stale client entry for this session in the `clients` array.
|
|
2360
|
+
* 4. On failure, waits `retryDelay` ms before the next attempt.
|
|
2361
|
+
*
|
|
2362
|
+
* If all attempts are exhausted, logs an error and returns silently (does not throw),
|
|
2363
|
+
* so a single bad server doesn't block the rest of the batch from connecting.
|
|
2364
|
+
*/
|
|
2365
|
+
async establishConnectionWithRetries(session) {
|
|
2366
|
+
const maxRetries = this.options.maxRetries ?? DEFAULT_MAX_RETRIES;
|
|
2367
|
+
const retryDelay = this.options.retryDelay ?? DEFAULT_RETRY_DELAY_MS;
|
|
2082
2368
|
let lastError;
|
|
2083
2369
|
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
2084
2370
|
try {
|
|
2085
|
-
const client =
|
|
2371
|
+
const client = new MCPClient({
|
|
2372
|
+
identity: this.identity,
|
|
2373
|
+
sessionId: session.sessionId,
|
|
2374
|
+
serverId: session.serverId,
|
|
2375
|
+
serverUrl: session.serverUrl,
|
|
2376
|
+
callbackUrl: session.callbackUrl,
|
|
2377
|
+
serverName: session.serverName,
|
|
2378
|
+
transportType: session.transportType,
|
|
2379
|
+
headers: session.headers
|
|
2380
|
+
});
|
|
2381
|
+
const timeoutMs = this.options.timeout ?? DEFAULT_TIMEOUT_MS;
|
|
2382
|
+
let timeoutTimer;
|
|
2383
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
2384
|
+
timeoutTimer = setTimeout(() => reject(new Error(`Connection timed out after ${timeoutMs}ms`)), timeoutMs);
|
|
2385
|
+
});
|
|
2386
|
+
try {
|
|
2387
|
+
await Promise.race([client.connect(), timeoutPromise]);
|
|
2388
|
+
} finally {
|
|
2389
|
+
clearTimeout(timeoutTimer);
|
|
2390
|
+
}
|
|
2391
|
+
this.clients = this.clients.filter((c) => c.getSessionId() !== session.sessionId);
|
|
2086
2392
|
this.clients.push(client);
|
|
2087
2393
|
return;
|
|
2088
2394
|
} catch (error) {
|
|
@@ -2094,36 +2400,32 @@ var MultiSessionClient = class {
|
|
|
2094
2400
|
}
|
|
2095
2401
|
console.error(`[MultiSessionClient] Failed to connect to session ${session.sessionId} after ${maxRetries + 1} attempts:`, lastError);
|
|
2096
2402
|
}
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
transportType: session.transportType,
|
|
2106
|
-
headers: session.headers
|
|
2107
|
-
});
|
|
2108
|
-
const timeoutMs = this.options.timeout ?? 15e3;
|
|
2109
|
-
const timeoutPromise = new Promise((_, reject) => {
|
|
2110
|
-
setTimeout(() => reject(new Error(`Connection timed out after ${timeoutMs}ms`)), timeoutMs);
|
|
2111
|
-
});
|
|
2112
|
-
await Promise.race([client.connect(), timeoutPromise]);
|
|
2113
|
-
return client;
|
|
2114
|
-
}
|
|
2403
|
+
/**
|
|
2404
|
+
* The main entry point. Fetches all active sessions for this identity from
|
|
2405
|
+
* storage and establishes connections to all of them in batches.
|
|
2406
|
+
*
|
|
2407
|
+
* Call this once after creating the client. On traditional servers, you can
|
|
2408
|
+
* cache the `MultiSessionClient` instance after calling `connect()` to avoid
|
|
2409
|
+
* re-fetching and re-connecting on every request.
|
|
2410
|
+
*/
|
|
2115
2411
|
async connect() {
|
|
2116
2412
|
const sessions = await this.getActiveSessions();
|
|
2117
2413
|
await this.connectInBatches(sessions);
|
|
2118
2414
|
}
|
|
2119
2415
|
/**
|
|
2120
|
-
* Returns
|
|
2416
|
+
* Returns all currently connected `MCPClient` instances.
|
|
2417
|
+
*
|
|
2418
|
+
* Use this to enumerate available tools across all connected servers,
|
|
2419
|
+
* or to route a tool call to the right client by `serverId`.
|
|
2121
2420
|
*/
|
|
2122
2421
|
getClients() {
|
|
2123
2422
|
return this.clients;
|
|
2124
2423
|
}
|
|
2125
2424
|
/**
|
|
2126
|
-
*
|
|
2425
|
+
* Gracefully disconnects all active MCP clients and clears the internal client list.
|
|
2426
|
+
*
|
|
2427
|
+
* Call this during server shutdown or when a user logs out to free up
|
|
2428
|
+
* underlying transport resources (SSE streams, HTTP connections, etc.).
|
|
2127
2429
|
*/
|
|
2128
2430
|
disconnect() {
|
|
2129
2431
|
this.clients.forEach((client) => client.disconnect());
|
|
@@ -2131,7 +2433,11 @@ var MultiSessionClient = class {
|
|
|
2131
2433
|
}
|
|
2132
2434
|
};
|
|
2133
2435
|
|
|
2436
|
+
// src/server/handlers/sse-handler.ts
|
|
2437
|
+
init_cjs_shims();
|
|
2438
|
+
|
|
2134
2439
|
// src/shared/event-routing.ts
|
|
2440
|
+
init_cjs_shims();
|
|
2135
2441
|
function isRpcResponseEvent(event) {
|
|
2136
2442
|
return "id" in event && ("result" in event || "error" in event);
|
|
2137
2443
|
}
|
|
@@ -2570,6 +2876,7 @@ function writeSSEEvent(res, event, data) {
|
|
|
2570
2876
|
}
|
|
2571
2877
|
|
|
2572
2878
|
// src/server/handlers/nextjs-handler.ts
|
|
2879
|
+
init_cjs_shims();
|
|
2573
2880
|
function createNextMcpHandler(options = {}) {
|
|
2574
2881
|
const {
|
|
2575
2882
|
getIdentity = (request) => new URL(request.url).searchParams.get("identity"),
|
|
@@ -2717,6 +3024,12 @@ data: ${JSON.stringify(data)}
|
|
|
2717
3024
|
}
|
|
2718
3025
|
return { GET, POST };
|
|
2719
3026
|
}
|
|
3027
|
+
|
|
3028
|
+
// src/client/index.ts
|
|
3029
|
+
init_cjs_shims();
|
|
3030
|
+
|
|
3031
|
+
// src/client/core/sse-client.ts
|
|
3032
|
+
init_cjs_shims();
|
|
2720
3033
|
var CONNECTION_EVENT_INTERVAL_MS = 300;
|
|
2721
3034
|
var SSEClient = class {
|
|
2722
3035
|
constructor(options) {
|
|
@@ -2965,6 +3278,9 @@ var SSEClient = class {
|
|
|
2965
3278
|
}
|
|
2966
3279
|
}
|
|
2967
3280
|
};
|
|
3281
|
+
|
|
3282
|
+
// src/client/core/app-host.ts
|
|
3283
|
+
init_cjs_shims();
|
|
2968
3284
|
var HOST_INFO = { name: "mcp-ts-host", version: "1.0.0" };
|
|
2969
3285
|
var SANDBOX_PERMISSIONS = [
|
|
2970
3286
|
"allow-scripts",
|
|
@@ -3262,7 +3578,11 @@ var AppHost = class {
|
|
|
3262
3578
|
}
|
|
3263
3579
|
};
|
|
3264
3580
|
|
|
3581
|
+
// src/shared/index.ts
|
|
3582
|
+
init_cjs_shims();
|
|
3583
|
+
|
|
3265
3584
|
// src/shared/types.ts
|
|
3585
|
+
init_cjs_shims();
|
|
3266
3586
|
function isConnectSuccess(response) {
|
|
3267
3587
|
return "success" in response && response.success === true;
|
|
3268
3588
|
}
|
|
@@ -3280,6 +3600,7 @@ function isCallToolSuccess(response) {
|
|
|
3280
3600
|
}
|
|
3281
3601
|
|
|
3282
3602
|
// src/shared/tool-utils.ts
|
|
3603
|
+
init_cjs_shims();
|
|
3283
3604
|
function getToolUiResourceUri(tool) {
|
|
3284
3605
|
const meta = tool._meta;
|
|
3285
3606
|
if (!meta?.ui) return void 0;
|