@mcp-ts/sdk 1.6.1 → 2.0.0

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.
Files changed (114) hide show
  1. package/README.md +12 -6
  2. package/dist/adapters/agui-adapter.d.mts +3 -3
  3. package/dist/adapters/agui-adapter.d.ts +3 -3
  4. package/dist/adapters/agui-adapter.js +4 -5
  5. package/dist/adapters/agui-adapter.js.map +1 -1
  6. package/dist/adapters/agui-adapter.mjs +4 -5
  7. package/dist/adapters/agui-adapter.mjs.map +1 -1
  8. package/dist/adapters/agui-middleware.d.mts +3 -3
  9. package/dist/adapters/agui-middleware.d.ts +3 -3
  10. package/dist/adapters/ai-adapter.d.mts +9 -3
  11. package/dist/adapters/ai-adapter.d.ts +9 -3
  12. package/dist/adapters/ai-adapter.js +20 -6
  13. package/dist/adapters/ai-adapter.js.map +1 -1
  14. package/dist/adapters/ai-adapter.mjs +20 -6
  15. package/dist/adapters/ai-adapter.mjs.map +1 -1
  16. package/dist/adapters/langchain-adapter.d.mts +3 -3
  17. package/dist/adapters/langchain-adapter.d.ts +3 -3
  18. package/dist/adapters/langchain-adapter.js +9 -6
  19. package/dist/adapters/langchain-adapter.js.map +1 -1
  20. package/dist/adapters/langchain-adapter.mjs +9 -6
  21. package/dist/adapters/langchain-adapter.mjs.map +1 -1
  22. package/dist/adapters/mastra-adapter.d.mts +1 -1
  23. package/dist/adapters/mastra-adapter.d.ts +1 -1
  24. package/dist/adapters/mastra-adapter.js +5 -1
  25. package/dist/adapters/mastra-adapter.js.map +1 -1
  26. package/dist/adapters/mastra-adapter.mjs +5 -1
  27. package/dist/adapters/mastra-adapter.mjs.map +1 -1
  28. package/dist/bin/mcp-ts.js +7 -1
  29. package/dist/bin/mcp-ts.js.map +1 -1
  30. package/dist/bin/mcp-ts.mjs +7 -1
  31. package/dist/bin/mcp-ts.mjs.map +1 -1
  32. package/dist/client/index.d.mts +2 -2
  33. package/dist/client/index.d.ts +2 -2
  34. package/dist/client/index.js +9 -13
  35. package/dist/client/index.js.map +1 -1
  36. package/dist/client/index.mjs +9 -13
  37. package/dist/client/index.mjs.map +1 -1
  38. package/dist/client/react.d.mts +7 -7
  39. package/dist/client/react.d.ts +7 -7
  40. package/dist/client/react.js +111 -63
  41. package/dist/client/react.js.map +1 -1
  42. package/dist/client/react.mjs +111 -63
  43. package/dist/client/react.mjs.map +1 -1
  44. package/dist/client/vue.d.mts +7 -7
  45. package/dist/client/vue.d.ts +7 -7
  46. package/dist/client/vue.js +14 -18
  47. package/dist/client/vue.js.map +1 -1
  48. package/dist/client/vue.mjs +14 -18
  49. package/dist/client/vue.mjs.map +1 -1
  50. package/dist/{index-DhA-OEAe.d.ts → index-C9gvpxy5.d.ts} +5 -5
  51. package/dist/{index-bFL4ZF2N.d.mts → index-eaH14_5u.d.mts} +5 -5
  52. package/dist/index.d.mts +6 -6
  53. package/dist/index.d.ts +6 -6
  54. package/dist/index.js +616 -370
  55. package/dist/index.js.map +1 -1
  56. package/dist/index.mjs +615 -370
  57. package/dist/index.mjs.map +1 -1
  58. package/dist/{multi-session-client-CHE8QpVE.d.ts → multi-session-client-BYtguGJm.d.ts} +22 -22
  59. package/dist/{multi-session-client-CQsRbxYI.d.mts → multi-session-client-DYNe6az3.d.mts} +22 -22
  60. package/dist/server/index.d.mts +31 -34
  61. package/dist/server/index.d.ts +31 -34
  62. package/dist/server/index.js +531 -256
  63. package/dist/server/index.js.map +1 -1
  64. package/dist/server/index.mjs +530 -256
  65. package/dist/server/index.mjs.map +1 -1
  66. package/dist/shared/index.d.mts +5 -5
  67. package/dist/shared/index.d.ts +5 -5
  68. package/dist/shared/index.js +76 -101
  69. package/dist/shared/index.js.map +1 -1
  70. package/dist/shared/index.mjs +76 -101
  71. package/dist/shared/index.mjs.map +1 -1
  72. package/dist/{tool-router-Dh2804tM.d.ts → tool-router-Ddtybmr0.d.ts} +71 -73
  73. package/dist/{tool-router-BVaV1udm.d.mts → tool-router-Dnd6IOKC.d.mts} +71 -73
  74. package/dist/{types-rIuN1CQi.d.mts → types-BCAG20P6.d.mts} +4 -4
  75. package/dist/{types-rIuN1CQi.d.ts → types-BCAG20P6.d.ts} +4 -4
  76. package/dist/{utils-0qmYrqoa.d.mts → utils-DELRKQPU.d.mts} +1 -1
  77. package/dist/{utils-0qmYrqoa.d.ts → utils-DELRKQPU.d.ts} +1 -1
  78. package/migrations/neon/20260513010000_install_mcp_sessions.sql +69 -0
  79. package/migrations/neon/20260513020000_add_session_cleanup_cron.sql +35 -0
  80. package/{supabase/migrations → migrations/supabase}/20260330195700_install_mcp_sessions.sql +7 -9
  81. package/package.json +14 -5
  82. package/src/adapters/ai-adapter.ts +30 -1
  83. package/src/adapters/langchain-adapter.ts +6 -2
  84. package/src/adapters/mastra-adapter.ts +6 -2
  85. package/src/bin/mcp-ts.ts +8 -1
  86. package/src/client/core/app-host.ts +1 -1
  87. package/src/client/core/sse-client.ts +12 -14
  88. package/src/client/core/types.ts +1 -1
  89. package/src/client/react/oauth-popup.tsx +111 -51
  90. package/src/client/react/use-mcp-apps.tsx +1 -1
  91. package/src/client/react/use-mcp.ts +11 -11
  92. package/src/client/vue/use-mcp.ts +10 -10
  93. package/src/server/handlers/nextjs-handler.ts +18 -15
  94. package/src/server/handlers/sse-handler.ts +29 -29
  95. package/src/server/index.ts +1 -1
  96. package/src/server/mcp/multi-session-client.ts +17 -17
  97. package/src/server/mcp/oauth-client.ts +37 -37
  98. package/src/server/mcp/storage-oauth-provider.ts +17 -17
  99. package/src/server/storage/file-backend.ts +25 -25
  100. package/src/server/storage/index.ts +67 -10
  101. package/src/server/storage/memory-backend.ts +34 -34
  102. package/src/server/storage/neon-backend.ts +281 -0
  103. package/src/server/storage/redis-backend.ts +64 -64
  104. package/src/server/storage/sqlite-backend.ts +33 -33
  105. package/src/server/storage/supabase-backend.ts +23 -24
  106. package/src/server/storage/types.ts +18 -21
  107. package/src/shared/errors.ts +1 -1
  108. package/src/shared/index.ts +1 -2
  109. package/src/shared/meta-tools.ts +4 -6
  110. package/src/shared/schema-compressor.ts +2 -42
  111. package/src/shared/tool-index.ts +89 -84
  112. package/src/shared/tool-router.ts +0 -24
  113. package/src/shared/types.ts +4 -4
  114. /package/{supabase/migrations → migrations/supabase}/20260421010000_add_session_cleanup_cron.sql +0 -0
@@ -28,8 +28,8 @@ var SSEClient = class {
28
28
  isConnected() {
29
29
  return this.connected;
30
30
  }
31
- async getSessions() {
32
- return this.sendRequest("getSessions");
31
+ async listSessions() {
32
+ return this.sendRequest("listSessions");
33
33
  }
34
34
  async connectToServer(params) {
35
35
  return this.sendRequest("connect", params);
@@ -45,8 +45,8 @@ var SSEClient = class {
45
45
  this.emitUiEventIfPresent(result, sessionId, toolName);
46
46
  return result;
47
47
  }
48
- async restoreSession(sessionId) {
49
- return this.sendRequest("restoreSession", { sessionId });
48
+ async getSession(sessionId) {
49
+ return this.sendRequest("getSession", { sessionId });
50
50
  }
51
51
  async finishAuth(sessionId, code) {
52
52
  return this.sendRequest("finishAuth", { sessionId, code });
@@ -112,7 +112,7 @@ var SSEClient = class {
112
112
  return this.parseRpcResponse(data2);
113
113
  }
114
114
  const data = await this.readRpcResponseFromStream(response, {
115
- delayConnectionEvents: method === "connect" || method === "restoreSession" || method === "finishAuth"
115
+ delayConnectionEvents: method === "connect" || method === "getSession" || method === "finishAuth"
116
116
  });
117
117
  return this.parseRpcResponse(data);
118
118
  }
@@ -202,17 +202,13 @@ var SSEClient = class {
202
202
  throw new Error("Invalid RPC response format");
203
203
  }
204
204
  buildUrl() {
205
- const url = new URL(this.options.url, globalThis.location?.origin);
206
- url.searchParams.set("identity", this.options.identity);
207
- if (this.options.authToken) {
208
- url.searchParams.set("token", this.options.authToken);
209
- }
210
- return url.toString();
205
+ return new URL(this.options.url, globalThis.location?.origin).toString();
211
206
  }
212
207
  buildHeaders() {
213
208
  const headers = {
214
209
  "Content-Type": "application/json",
215
- "Accept": "text/event-stream"
210
+ "Accept": "text/event-stream",
211
+ "x-mcp-user-id": this.options.userId
216
212
  };
217
213
  if (this.options.authToken) {
218
214
  headers["Authorization"] = `Bearer ${this.options.authToken}`;
@@ -259,7 +255,7 @@ var SSEClient = class {
259
255
  function useMcp(options) {
260
256
  const {
261
257
  url,
262
- identity,
258
+ userId,
263
259
  authToken,
264
260
  autoConnect = true,
265
261
  autoInitialize = true,
@@ -280,7 +276,7 @@ function useMcp(options) {
280
276
  isMountedRef.current = true;
281
277
  const clientOptions = {
282
278
  url,
283
- identity,
279
+ userId,
284
280
  authToken,
285
281
  onConnectionEvent: (event) => {
286
282
  updateConnectionsFromEvent(event);
@@ -309,7 +305,7 @@ function useMcp(options) {
309
305
  isMountedRef.current = false;
310
306
  client.disconnect();
311
307
  };
312
- }, [url, identity, authToken, autoConnect, autoInitialize]);
308
+ }, [url, userId, authToken, autoConnect, autoInitialize]);
313
309
  const updateConnectionsFromEvent = useCallback((event) => {
314
310
  if (!isMountedRef.current) return;
315
311
  const isTransientReconnectState = (state) => state === "INITIALIZING" || state === "VALIDATING" || state === "RECONNECTING" || state === "CONNECTING" || state === "CONNECTED" || state === "DISCOVERING";
@@ -404,7 +400,7 @@ function useMcp(options) {
404
400
  if (!clientRef.current) return;
405
401
  try {
406
402
  setIsInitializing(true);
407
- const result = await clientRef.current.getSessions();
403
+ const result = await clientRef.current.listSessions();
408
404
  const sessions = result.sessions || [];
409
405
  if (isMountedRef.current) {
410
406
  setConnections(
@@ -428,7 +424,7 @@ function useMcp(options) {
428
424
  return;
429
425
  }
430
426
  suppressAuthRedirectSessionsRef.current.add(session.sessionId);
431
- await clientRef.current.restoreSession(session.sessionId);
427
+ await clientRef.current.getSession(session.sessionId);
432
428
  } catch (error) {
433
429
  console.error(`[useMcp] Failed to validate session ${session.sessionId}:`, error);
434
430
  } finally {
@@ -506,7 +502,7 @@ function useMcp(options) {
506
502
  throw new Error("SSE client not initialized");
507
503
  }
508
504
  suppressAuthRedirectSessionsRef.current.delete(sessionId);
509
- await clientRef.current.restoreSession(sessionId);
505
+ await clientRef.current.getSession(sessionId);
510
506
  }, []);
511
507
  const callTool = useCallback(
512
508
  async (sessionId, toolName, toolArgs) => {
@@ -625,14 +621,31 @@ function useMcp(options) {
625
621
  }
626
622
  var AUTH_CODE_MESSAGE = "MCP_AUTH_CODE";
627
623
  var AUTH_RESULT_MESSAGE = "MCP_AUTH_RESULT";
624
+ var AUTH_CHANNEL_NAME = "mcp-auth-channel";
625
+ function createAuthBroadcastChannel() {
626
+ if (typeof BroadcastChannel === "undefined") {
627
+ return null;
628
+ }
629
+ try {
630
+ return new BroadcastChannel(AUTH_CHANNEL_NAME);
631
+ } catch {
632
+ return null;
633
+ }
634
+ }
628
635
  function postPopupResult(popupWindow, result) {
629
- popupWindow?.postMessage(
630
- {
631
- type: AUTH_RESULT_MESSAGE,
632
- ...result
633
- },
634
- window.location.origin
635
- );
636
+ const payload = {
637
+ type: AUTH_RESULT_MESSAGE,
638
+ ...result
639
+ };
640
+ try {
641
+ popupWindow?.postMessage(payload, window.location.origin);
642
+ } catch {
643
+ }
644
+ const channel = createAuthBroadcastChannel();
645
+ if (channel) {
646
+ channel.postMessage(payload);
647
+ channel.close();
648
+ }
636
649
  }
637
650
  function openCenteredPopup(url, options = {}) {
638
651
  const {
@@ -673,60 +686,87 @@ function createOAuthPopupRedirectHandler(options = {}) {
673
686
  }
674
687
  function useMcpOAuthPopup(connections, finishAuth) {
675
688
  const pendingPopupsRef = useRef(/* @__PURE__ */ new Map());
689
+ const processingCodesRef = useRef(/* @__PURE__ */ new Set());
676
690
  useEffect(() => {
677
691
  const handleMessage = async (event) => {
678
- if (event.origin !== window.location.origin) {
692
+ if (event.origin && event.origin !== window.location.origin) {
679
693
  return;
680
694
  }
681
- if (event.data?.type !== AUTH_CODE_MESSAGE || !event.data.code) {
695
+ const code = typeof event.data?.code === "string" ? event.data.code : "";
696
+ if (event.data?.type !== AUTH_CODE_MESSAGE || !code) {
682
697
  return;
683
698
  }
684
699
  const popupWindow = event.source && "postMessage" in event.source ? event.source : null;
685
700
  const targetSessionId = typeof event.data.sessionId === "string" ? event.data.sessionId : "";
701
+ if (popupWindow && targetSessionId) {
702
+ pendingPopupsRef.current.set(targetSessionId, popupWindow);
703
+ }
686
704
  if (!targetSessionId) {
687
- postPopupResult(popupWindow, {
688
- success: false,
689
- error: "Missing OAuth session identifier"
690
- });
705
+ if (popupWindow) {
706
+ postPopupResult(popupWindow, {
707
+ success: false,
708
+ error: "Missing OAuth session identifier"
709
+ });
710
+ }
691
711
  return;
692
712
  }
693
713
  const targetSession = connections.find((connection) => connection.sessionId === targetSessionId);
694
714
  if (!targetSession) {
695
- postPopupResult(popupWindow, {
696
- sessionId: targetSessionId,
697
- success: false,
698
- error: "OAuth session not found in the current client state"
699
- });
715
+ if (popupWindow) {
716
+ postPopupResult(popupWindow, {
717
+ sessionId: targetSessionId,
718
+ success: false,
719
+ error: "OAuth session not found in the current client state"
720
+ });
721
+ }
700
722
  return;
701
723
  }
702
- if (popupWindow) {
703
- pendingPopupsRef.current.set(targetSession.sessionId, popupWindow);
724
+ const codeKey = `${targetSession.sessionId}:${code}`;
725
+ if (processingCodesRef.current.has(codeKey)) {
726
+ return;
704
727
  }
728
+ processingCodesRef.current.add(codeKey);
705
729
  try {
706
- await finishAuth(targetSession.sessionId, event.data.code);
730
+ await finishAuth(targetSession.sessionId, code);
707
731
  } catch (error) {
732
+ processingCodesRef.current.delete(codeKey);
708
733
  pendingPopupsRef.current.delete(targetSession.sessionId);
709
- postPopupResult(popupWindow, {
710
- sessionId: targetSession.sessionId,
711
- success: false,
712
- error: error instanceof Error ? error.message : "Failed to finish auth"
713
- });
734
+ if (popupWindow) {
735
+ postPopupResult(popupWindow, {
736
+ sessionId: targetSession.sessionId,
737
+ success: false,
738
+ error: error instanceof Error ? error.message : "Failed to finish auth"
739
+ });
740
+ }
741
+ }
742
+ };
743
+ const channel = createAuthBroadcastChannel();
744
+ const handleChannelMessage = (event) => {
745
+ if (event.data?.type === AUTH_CODE_MESSAGE) {
746
+ void handleMessage(event);
714
747
  }
715
748
  };
716
749
  window.addEventListener("message", handleMessage);
717
- return () => window.removeEventListener("message", handleMessage);
750
+ channel?.addEventListener("message", handleChannelMessage);
751
+ return () => {
752
+ window.removeEventListener("message", handleMessage);
753
+ channel?.removeEventListener("message", handleChannelMessage);
754
+ channel?.close();
755
+ };
718
756
  }, [connections, finishAuth]);
719
757
  useEffect(() => {
720
758
  for (const connection of connections) {
721
- const popupWindow = pendingPopupsRef.current.get(connection.sessionId);
722
- if (!popupWindow) {
723
- continue;
724
- }
725
- if (connection.state === "AUTHENTICATED") {
759
+ const popupWindow = pendingPopupsRef.current.get(connection.sessionId) || null;
760
+ if (connection.state === "AUTHENTICATED" || connection.state === "READY" || connection.state === "CONNECTED") {
726
761
  postPopupResult(popupWindow, {
727
762
  sessionId: connection.sessionId,
728
763
  success: true
729
764
  });
765
+ for (const codeKey of processingCodesRef.current) {
766
+ if (codeKey.startsWith(`${connection.sessionId}:`)) {
767
+ processingCodesRef.current.delete(codeKey);
768
+ }
769
+ }
730
770
  pendingPopupsRef.current.delete(connection.sessionId);
731
771
  continue;
732
772
  }
@@ -736,6 +776,11 @@ function useMcpOAuthPopup(connections, finishAuth) {
736
776
  success: false,
737
777
  error: connection.error || "Failed to complete authorization"
738
778
  });
779
+ for (const codeKey of processingCodesRef.current) {
780
+ if (codeKey.startsWith(`${connection.sessionId}:`)) {
781
+ processingCodesRef.current.delete(codeKey);
782
+ }
783
+ }
739
784
  pendingPopupsRef.current.delete(connection.sessionId);
740
785
  }
741
786
  }
@@ -756,10 +801,9 @@ function McpOAuthCallbackContent({
756
801
  }) {
757
802
  const [phase, setPhase] = useState(debugPhase || "loading");
758
803
  const [errorMessage, setErrorMessage] = useState("");
759
- const openerMissing = typeof window !== "undefined" ? !window.opener : false;
760
804
  const missingCode = !code;
761
805
  const missingSessionId = !sessionId;
762
- const blockingError = openerMissing ? "Error: No opener window found. This window should be opened from the app." : missingCode ? "Error: No authorization code received." : missingSessionId ? "Error: No OAuth state received." : null;
806
+ const blockingError = missingCode ? "Error: No authorization code received." : missingSessionId ? "Error: No OAuth state received." : null;
763
807
  useEffect(() => {
764
808
  if (debugPhase) {
765
809
  setPhase(debugPhase);
@@ -772,8 +816,9 @@ function McpOAuthCallbackContent({
772
816
  return;
773
817
  }
774
818
  let closed = false;
819
+ const channel = createAuthBroadcastChannel();
775
820
  const handleResult = (event) => {
776
- if (event.origin !== window.location.origin) {
821
+ if (event.origin && event.origin !== window.location.origin) {
777
822
  return;
778
823
  }
779
824
  if (event.data?.type !== AUTH_RESULT_MESSAGE) {
@@ -785,6 +830,7 @@ function McpOAuthCallbackContent({
785
830
  if (event.data.success) {
786
831
  setPhase("success");
787
832
  window.removeEventListener("message", handleResult);
833
+ channel?.close();
788
834
  closed = true;
789
835
  window.setTimeout(() => window.close(), 1200);
790
836
  return;
@@ -794,21 +840,23 @@ function McpOAuthCallbackContent({
794
840
  setErrorMessage(message);
795
841
  };
796
842
  window.addEventListener("message", handleResult);
797
- try {
798
- window.opener.postMessage(
799
- { type: AUTH_CODE_MESSAGE, code, sessionId },
800
- window.location.origin
801
- );
802
- } catch (error) {
803
- console.error("Failed to communicate with opener:", error);
804
- window.setTimeout(() => {
843
+ channel?.addEventListener("message", handleResult);
844
+ const payload = { type: AUTH_CODE_MESSAGE, code, sessionId };
845
+ if (window.opener) {
846
+ try {
847
+ window.opener.postMessage(payload, window.location.origin);
848
+ } catch {
805
849
  setPhase("error");
806
850
  setErrorMessage("Error: Could not communicate with main window.");
807
- }, 0);
851
+ }
852
+ }
853
+ if (channel) {
854
+ channel.postMessage(payload);
808
855
  }
809
856
  return () => {
810
857
  if (!closed) {
811
858
  window.removeEventListener("message", handleResult);
859
+ channel?.close();
812
860
  }
813
861
  };
814
862
  }, [blockingError, code, sessionId, debugPhase]);
@@ -1342,7 +1390,7 @@ var AppHost = class {
1342
1390
  async getSessionId() {
1343
1391
  if (this.sessionId) return this.sessionId;
1344
1392
  if (!this.client) return void 0;
1345
- const result = await this.client.getSessions();
1393
+ const result = await this.client.listSessions();
1346
1394
  return result.sessions?.[0]?.sessionId;
1347
1395
  }
1348
1396
  isMcpUri(url) {