@mcp-ts/sdk 1.3.5 → 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/dist/index.mjs CHANGED
@@ -144,6 +144,14 @@ var RedisStorageBackend = class {
144
144
  __publicField(this, "IDENTITY_KEY_PREFIX", "mcp:identity:");
145
145
  __publicField(this, "IDENTITY_KEY_SUFFIX", ":sessions");
146
146
  }
147
+ async init() {
148
+ try {
149
+ await this.redis.ping();
150
+ console.log("[mcp-ts][Storage] Redis: \u2713 Connected to server.");
151
+ } catch (error) {
152
+ throw new Error(`[RedisStorage] Failed to connect to Redis: ${error.message}`);
153
+ }
154
+ }
147
155
  /**
148
156
  * Generates Redis key for a specific session
149
157
  * @private
@@ -369,6 +377,9 @@ var MemoryStorageBackend = class {
369
377
  // Map<identity, Set<sessionId>>
370
378
  __publicField(this, "identitySessions", /* @__PURE__ */ new Map());
371
379
  }
380
+ async init() {
381
+ console.log("[mcp-ts][Storage] Memory: \u2713 internal memory store active.");
382
+ }
372
383
  getSessionKey(identity, sessionId) {
373
384
  return `${identity}:${sessionId}`;
374
385
  }
@@ -488,6 +499,7 @@ var FileStorageBackend = class {
488
499
  }
489
500
  }
490
501
  this.initialized = true;
502
+ console.log(`[mcp-ts][Storage] File: \u2713 storage directory at ${path.dirname(this.filePath)} verified.`);
491
503
  }
492
504
  async ensureInitialized() {
493
505
  if (!this.initialized) await this.init();
@@ -592,6 +604,7 @@ var SqliteStorage = class {
592
604
  CREATE INDEX IF NOT EXISTS idx_${this.table}_identity ON ${this.table}(identity);
593
605
  `);
594
606
  this.initialized = true;
607
+ console.log(`[mcp-ts][Storage] SQLite: \u2713 database at ${this.dbPath} verified.`);
595
608
  } catch (error) {
596
609
  if (error.code === "MODULE_NOT_FOUND" || error.message?.includes("better-sqlite3")) {
597
610
  throw new Error(
@@ -707,6 +720,157 @@ var SqliteStorage = class {
707
720
  }
708
721
  };
709
722
 
723
+ // src/server/storage/supabase-backend.ts
724
+ var SupabaseStorageBackend = class {
725
+ constructor(supabase) {
726
+ this.supabase = supabase;
727
+ __publicField(this, "DEFAULT_TTL", SESSION_TTL_SECONDS);
728
+ }
729
+ async init() {
730
+ const { error } = await this.supabase.from("mcp_sessions").select("session_id").limit(0);
731
+ if (error) {
732
+ if (error.code === "42P01") {
733
+ throw new Error(
734
+ '[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.'
735
+ );
736
+ }
737
+ throw new Error(`[SupabaseStorage] Initialization check failed: ${error.message}`);
738
+ }
739
+ console.log('[mcp-ts][Storage] Supabase: \u2713 "mcp_sessions" table verified.');
740
+ }
741
+ generateSessionId() {
742
+ return crypto.randomUUID();
743
+ }
744
+ mapRowToSessionData(row) {
745
+ return {
746
+ sessionId: row.session_id,
747
+ serverId: row.server_id,
748
+ serverName: row.server_name,
749
+ serverUrl: row.server_url,
750
+ transportType: row.transport_type,
751
+ callbackUrl: row.callback_url,
752
+ createdAt: new Date(row.created_at).getTime(),
753
+ identity: row.identity,
754
+ headers: row.headers,
755
+ active: row.active,
756
+ clientInformation: row.client_information,
757
+ tokens: row.tokens,
758
+ codeVerifier: row.code_verifier,
759
+ clientId: row.client_id
760
+ };
761
+ }
762
+ async createSession(session, ttl) {
763
+ const { sessionId, identity } = session;
764
+ if (!sessionId || !identity) throw new Error("identity and sessionId required");
765
+ const effectiveTtl = ttl ?? this.DEFAULT_TTL;
766
+ const expiresAt = new Date(Date.now() + effectiveTtl * 1e3).toISOString();
767
+ const { error } = await this.supabase.from("mcp_sessions").insert({
768
+ session_id: sessionId,
769
+ user_id: identity,
770
+ // Maps user_id to identity to support RLS using auth.uid()
771
+ server_id: session.serverId,
772
+ server_name: session.serverName,
773
+ server_url: session.serverUrl,
774
+ transport_type: session.transportType,
775
+ callback_url: session.callbackUrl,
776
+ created_at: new Date(session.createdAt || Date.now()).toISOString(),
777
+ identity,
778
+ headers: session.headers,
779
+ active: session.active ?? false,
780
+ client_information: session.clientInformation,
781
+ tokens: session.tokens,
782
+ code_verifier: session.codeVerifier,
783
+ client_id: session.clientId,
784
+ expires_at: expiresAt
785
+ });
786
+ if (error) {
787
+ if (error.code === "23505") {
788
+ throw new Error(`Session ${sessionId} already exists`);
789
+ }
790
+ throw new Error(`Failed to create session in Supabase: ${error.message}`);
791
+ }
792
+ }
793
+ async updateSession(identity, sessionId, data, ttl) {
794
+ const effectiveTtl = ttl ?? this.DEFAULT_TTL;
795
+ const expiresAt = new Date(Date.now() + effectiveTtl * 1e3).toISOString();
796
+ const updateData = {
797
+ expires_at: expiresAt,
798
+ updated_at: (/* @__PURE__ */ new Date()).toISOString()
799
+ };
800
+ if ("serverId" in data) updateData.server_id = data.serverId;
801
+ if ("serverName" in data) updateData.server_name = data.serverName;
802
+ if ("serverUrl" in data) updateData.server_url = data.serverUrl;
803
+ if ("transportType" in data) updateData.transport_type = data.transportType;
804
+ if ("callbackUrl" in data) updateData.callback_url = data.callbackUrl;
805
+ if ("active" in data) updateData.active = data.active;
806
+ if ("headers" in data) updateData.headers = data.headers;
807
+ if ("clientInformation" in data) updateData.client_information = data.clientInformation;
808
+ if ("tokens" in data) updateData.tokens = data.tokens;
809
+ if ("codeVerifier" in data) updateData.code_verifier = data.codeVerifier;
810
+ if ("clientId" in data) updateData.client_id = data.clientId;
811
+ const { data: updatedRows, error } = await this.supabase.from("mcp_sessions").update(updateData).eq("identity", identity).eq("session_id", sessionId).select("id");
812
+ if (error) {
813
+ throw new Error(`Failed to update session: ${error.message}`);
814
+ }
815
+ if (!updatedRows || updatedRows.length === 0) {
816
+ throw new Error(`Session ${sessionId} not found for identity ${identity}`);
817
+ }
818
+ }
819
+ async getSession(identity, sessionId) {
820
+ const { data, error } = await this.supabase.from("mcp_sessions").select("*").eq("identity", identity).eq("session_id", sessionId).maybeSingle();
821
+ if (error) {
822
+ console.error("[SupabaseStorage] Failed to get session:", error);
823
+ return null;
824
+ }
825
+ if (!data) return null;
826
+ return this.mapRowToSessionData(data);
827
+ }
828
+ async getIdentitySessionsData(identity) {
829
+ const { data, error } = await this.supabase.from("mcp_sessions").select("*").eq("identity", identity);
830
+ if (error) {
831
+ console.error(`[SupabaseStorage] Failed to get session data for ${identity}:`, error);
832
+ return [];
833
+ }
834
+ return data.map((row) => this.mapRowToSessionData(row));
835
+ }
836
+ async removeSession(identity, sessionId) {
837
+ const { error } = await this.supabase.from("mcp_sessions").delete().eq("identity", identity).eq("session_id", sessionId);
838
+ if (error) {
839
+ console.error("[SupabaseStorage] Failed to remove session:", error);
840
+ }
841
+ }
842
+ async getIdentityMcpSessions(identity) {
843
+ const { data, error } = await this.supabase.from("mcp_sessions").select("session_id").eq("identity", identity);
844
+ if (error) {
845
+ console.error(`[SupabaseStorage] Failed to get sessions for ${identity}:`, error);
846
+ return [];
847
+ }
848
+ return data.map((row) => row.session_id);
849
+ }
850
+ async getAllSessionIds() {
851
+ const { data, error } = await this.supabase.from("mcp_sessions").select("session_id");
852
+ if (error) {
853
+ console.error("[SupabaseStorage] Failed to get all sessions:", error);
854
+ return [];
855
+ }
856
+ return data.map((row) => row.session_id);
857
+ }
858
+ async clearAll() {
859
+ const { error } = await this.supabase.from("mcp_sessions").delete().neq("session_id", "");
860
+ if (error) {
861
+ console.error("[SupabaseStorage] Failed to clear sessions:", error);
862
+ }
863
+ }
864
+ async cleanupExpiredSessions() {
865
+ const { error } = await this.supabase.from("mcp_sessions").delete().lt("expires_at", (/* @__PURE__ */ new Date()).toISOString());
866
+ if (error) {
867
+ console.error("[SupabaseStorage] Failed to cleanup expired sessions:", error);
868
+ }
869
+ }
870
+ async disconnect() {
871
+ }
872
+ };
873
+
710
874
  // src/server/storage/index.ts
711
875
  var storageInstance = null;
712
876
  var storagePromise = null;
@@ -725,53 +889,85 @@ async function createStorage() {
725
889
  try {
726
890
  const { getRedis: getRedis2 } = await Promise.resolve().then(() => (init_redis(), redis_exports));
727
891
  const redis2 = await getRedis2();
728
- console.log("[Storage] Using Redis storage (Explicit)");
729
- return new RedisStorageBackend(redis2);
892
+ console.log('[mcp-ts][Storage] Explicit selection: "redis"');
893
+ return await initializeStorage(new RedisStorageBackend(redis2));
730
894
  } catch (error) {
731
- console.error("[Storage] Failed to initialize Redis:", error.message);
732
- console.log("[Storage] Falling back to In-Memory storage");
733
- return new MemoryStorageBackend();
895
+ console.error("[mcp-ts][Storage] Failed to initialize Redis:", error.message);
896
+ console.log("[mcp-ts][Storage] Falling back to In-Memory storage");
897
+ return await initializeStorage(new MemoryStorageBackend());
734
898
  }
735
899
  }
736
900
  if (type === "file") {
737
901
  const filePath = process.env.MCP_TS_STORAGE_FILE;
738
- if (!filePath) {
739
- console.warn('[Storage] MCP_TS_STORAGE_TYPE is "file" but MCP_TS_STORAGE_FILE is missing');
740
- }
741
- console.log(`[Storage] Using File storage (${filePath}) (Explicit)`);
902
+ console.log(`[mcp-ts][Storage] Explicit selection: "file" (${filePath || "default"})`);
742
903
  return await initializeStorage(new FileStorageBackend({ path: filePath }));
743
904
  }
744
905
  if (type === "sqlite") {
745
906
  const dbPath = process.env.MCP_TS_STORAGE_SQLITE_PATH;
746
- console.log(`[Storage] Using SQLite storage (${dbPath || "default"}) (Explicit)`);
907
+ console.log(`[mcp-ts][Storage] Explicit selection: "sqlite" (${dbPath || "default"})`);
747
908
  return await initializeStorage(new SqliteStorage({ path: dbPath }));
748
909
  }
910
+ if (type === "supabase") {
911
+ const url = process.env.SUPABASE_URL;
912
+ const key = process.env.SUPABASE_SERVICE_ROLE_KEY || process.env.SUPABASE_ANON_KEY;
913
+ if (!url || !key) {
914
+ console.warn('[mcp-ts][Storage] Explicit selection "supabase" requires SUPABASE_URL and SUPABASE_SERVICE_ROLE_KEY.');
915
+ } else {
916
+ if (!process.env.SUPABASE_SERVICE_ROLE_KEY) {
917
+ 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.');
918
+ }
919
+ try {
920
+ const { createClient } = await import('@supabase/supabase-js');
921
+ const client = createClient(url, key);
922
+ console.log('[mcp-ts][Storage] Explicit selection: "supabase"');
923
+ return await initializeStorage(new SupabaseStorageBackend(client));
924
+ } catch (error) {
925
+ console.error("[mcp-ts][Storage] Failed to initialize Supabase:", error.message);
926
+ console.log("[mcp-ts][Storage] Falling back to In-Memory storage");
927
+ return await initializeStorage(new MemoryStorageBackend());
928
+ }
929
+ }
930
+ }
749
931
  if (type === "memory") {
750
- console.log("[Storage] Using In-Memory storage (Explicit)");
751
- return new MemoryStorageBackend();
932
+ console.log('[mcp-ts][Storage] Explicit selection: "memory"');
933
+ return await initializeStorage(new MemoryStorageBackend());
752
934
  }
753
935
  if (process.env.REDIS_URL) {
754
936
  try {
755
937
  const { getRedis: getRedis2 } = await Promise.resolve().then(() => (init_redis(), redis_exports));
756
938
  const redis2 = await getRedis2();
757
- console.log("[Storage] Auto-detected REDIS_URL. Using Redis storage.");
758
- return new RedisStorageBackend(redis2);
939
+ console.log('[mcp-ts][Storage] Auto-detection: "redis" (via REDIS_URL)');
940
+ return await initializeStorage(new RedisStorageBackend(redis2));
759
941
  } catch (error) {
760
- console.error("[Storage] Redis auto-detection failed:", error.message);
761
- console.log("[Storage] Falling back to In-Memory storage");
762
- return new MemoryStorageBackend();
942
+ console.error("[mcp-ts][Storage] Redis auto-detection failed:", error.message);
943
+ console.log("[mcp-ts][Storage] Falling back to next available backend");
763
944
  }
764
945
  }
765
946
  if (process.env.MCP_TS_STORAGE_FILE) {
766
- console.log(`[Storage] Auto-detected MCP_TS_STORAGE_FILE. Using File storage (${process.env.MCP_TS_STORAGE_FILE}).`);
947
+ console.log(`[mcp-ts][Storage] Auto-detection: "file" (${process.env.MCP_TS_STORAGE_FILE})`);
767
948
  return await initializeStorage(new FileStorageBackend({ path: process.env.MCP_TS_STORAGE_FILE }));
768
949
  }
769
950
  if (process.env.MCP_TS_STORAGE_SQLITE_PATH) {
770
- console.log(`[Storage] Auto-detected MCP_TS_STORAGE_SQLITE_PATH. Using SQLite storage (${process.env.MCP_TS_STORAGE_SQLITE_PATH}).`);
951
+ console.log(`[mcp-ts][Storage] Auto-detection: "sqlite" (${process.env.MCP_TS_STORAGE_SQLITE_PATH})`);
771
952
  return await initializeStorage(new SqliteStorage({ path: process.env.MCP_TS_STORAGE_SQLITE_PATH }));
772
953
  }
773
- console.log("[Storage] No storage configured. Using In-Memory storage (Default).");
774
- return new MemoryStorageBackend();
954
+ if (process.env.SUPABASE_URL && (process.env.SUPABASE_SERVICE_ROLE_KEY || process.env.SUPABASE_ANON_KEY)) {
955
+ try {
956
+ const { createClient } = await import('@supabase/supabase-js');
957
+ const url = process.env.SUPABASE_URL;
958
+ const key = process.env.SUPABASE_SERVICE_ROLE_KEY || process.env.SUPABASE_ANON_KEY;
959
+ if (!process.env.SUPABASE_SERVICE_ROLE_KEY) {
960
+ 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.');
961
+ }
962
+ const client = createClient(url, key);
963
+ console.log('[mcp-ts][Storage] Auto-detection: "supabase" (via SUPABASE_URL)');
964
+ return await initializeStorage(new SupabaseStorageBackend(client));
965
+ } catch (error) {
966
+ console.error("[mcp-ts][Storage] Supabase auto-detection failed:", error.message);
967
+ }
968
+ }
969
+ console.log('[mcp-ts][Storage] Defaulting to: "memory"');
970
+ return await initializeStorage(new MemoryStorageBackend());
775
971
  }
776
972
  async function getStorage() {
777
973
  if (storageInstance) {