@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
@@ -30,8 +30,8 @@ var SSEClient = class {
30
30
  isConnected() {
31
31
  return this.connected;
32
32
  }
33
- async getSessions() {
34
- return this.sendRequest("getSessions");
33
+ async listSessions() {
34
+ return this.sendRequest("listSessions");
35
35
  }
36
36
  async connectToServer(params) {
37
37
  return this.sendRequest("connect", params);
@@ -47,8 +47,8 @@ var SSEClient = class {
47
47
  this.emitUiEventIfPresent(result, sessionId, toolName);
48
48
  return result;
49
49
  }
50
- async restoreSession(sessionId) {
51
- return this.sendRequest("restoreSession", { sessionId });
50
+ async getSession(sessionId) {
51
+ return this.sendRequest("getSession", { sessionId });
52
52
  }
53
53
  async finishAuth(sessionId, code) {
54
54
  return this.sendRequest("finishAuth", { sessionId, code });
@@ -114,7 +114,7 @@ var SSEClient = class {
114
114
  return this.parseRpcResponse(data2);
115
115
  }
116
116
  const data = await this.readRpcResponseFromStream(response, {
117
- delayConnectionEvents: method === "connect" || method === "restoreSession" || method === "finishAuth"
117
+ delayConnectionEvents: method === "connect" || method === "getSession" || method === "finishAuth"
118
118
  });
119
119
  return this.parseRpcResponse(data);
120
120
  }
@@ -204,17 +204,13 @@ var SSEClient = class {
204
204
  throw new Error("Invalid RPC response format");
205
205
  }
206
206
  buildUrl() {
207
- const url = new URL(this.options.url, globalThis.location?.origin);
208
- url.searchParams.set("identity", this.options.identity);
209
- if (this.options.authToken) {
210
- url.searchParams.set("token", this.options.authToken);
211
- }
212
- return url.toString();
207
+ return new URL(this.options.url, globalThis.location?.origin).toString();
213
208
  }
214
209
  buildHeaders() {
215
210
  const headers = {
216
211
  "Content-Type": "application/json",
217
- "Accept": "text/event-stream"
212
+ "Accept": "text/event-stream",
213
+ "x-mcp-user-id": this.options.userId
218
214
  };
219
215
  if (this.options.authToken) {
220
216
  headers["Authorization"] = `Bearer ${this.options.authToken}`;
@@ -261,7 +257,7 @@ var SSEClient = class {
261
257
  function useMcp(options) {
262
258
  const {
263
259
  url,
264
- identity,
260
+ userId,
265
261
  authToken,
266
262
  autoConnect = true,
267
263
  autoInitialize = true,
@@ -282,7 +278,7 @@ function useMcp(options) {
282
278
  isMountedRef.current = true;
283
279
  const clientOptions = {
284
280
  url,
285
- identity,
281
+ userId,
286
282
  authToken,
287
283
  onConnectionEvent: (event) => {
288
284
  updateConnectionsFromEvent(event);
@@ -311,7 +307,7 @@ function useMcp(options) {
311
307
  isMountedRef.current = false;
312
308
  client.disconnect();
313
309
  };
314
- }, [url, identity, authToken, autoConnect, autoInitialize]);
310
+ }, [url, userId, authToken, autoConnect, autoInitialize]);
315
311
  const updateConnectionsFromEvent = react.useCallback((event) => {
316
312
  if (!isMountedRef.current) return;
317
313
  const isTransientReconnectState = (state) => state === "INITIALIZING" || state === "VALIDATING" || state === "RECONNECTING" || state === "CONNECTING" || state === "CONNECTED" || state === "DISCOVERING";
@@ -406,7 +402,7 @@ function useMcp(options) {
406
402
  if (!clientRef.current) return;
407
403
  try {
408
404
  setIsInitializing(true);
409
- const result = await clientRef.current.getSessions();
405
+ const result = await clientRef.current.listSessions();
410
406
  const sessions = result.sessions || [];
411
407
  if (isMountedRef.current) {
412
408
  setConnections(
@@ -430,7 +426,7 @@ function useMcp(options) {
430
426
  return;
431
427
  }
432
428
  suppressAuthRedirectSessionsRef.current.add(session.sessionId);
433
- await clientRef.current.restoreSession(session.sessionId);
429
+ await clientRef.current.getSession(session.sessionId);
434
430
  } catch (error) {
435
431
  console.error(`[useMcp] Failed to validate session ${session.sessionId}:`, error);
436
432
  } finally {
@@ -508,7 +504,7 @@ function useMcp(options) {
508
504
  throw new Error("SSE client not initialized");
509
505
  }
510
506
  suppressAuthRedirectSessionsRef.current.delete(sessionId);
511
- await clientRef.current.restoreSession(sessionId);
507
+ await clientRef.current.getSession(sessionId);
512
508
  }, []);
513
509
  const callTool = react.useCallback(
514
510
  async (sessionId, toolName, toolArgs) => {
@@ -627,14 +623,31 @@ function useMcp(options) {
627
623
  }
628
624
  var AUTH_CODE_MESSAGE = "MCP_AUTH_CODE";
629
625
  var AUTH_RESULT_MESSAGE = "MCP_AUTH_RESULT";
626
+ var AUTH_CHANNEL_NAME = "mcp-auth-channel";
627
+ function createAuthBroadcastChannel() {
628
+ if (typeof BroadcastChannel === "undefined") {
629
+ return null;
630
+ }
631
+ try {
632
+ return new BroadcastChannel(AUTH_CHANNEL_NAME);
633
+ } catch {
634
+ return null;
635
+ }
636
+ }
630
637
  function postPopupResult(popupWindow, result) {
631
- popupWindow?.postMessage(
632
- {
633
- type: AUTH_RESULT_MESSAGE,
634
- ...result
635
- },
636
- window.location.origin
637
- );
638
+ const payload = {
639
+ type: AUTH_RESULT_MESSAGE,
640
+ ...result
641
+ };
642
+ try {
643
+ popupWindow?.postMessage(payload, window.location.origin);
644
+ } catch {
645
+ }
646
+ const channel = createAuthBroadcastChannel();
647
+ if (channel) {
648
+ channel.postMessage(payload);
649
+ channel.close();
650
+ }
638
651
  }
639
652
  function openCenteredPopup(url, options = {}) {
640
653
  const {
@@ -675,60 +688,87 @@ function createOAuthPopupRedirectHandler(options = {}) {
675
688
  }
676
689
  function useMcpOAuthPopup(connections, finishAuth) {
677
690
  const pendingPopupsRef = react.useRef(/* @__PURE__ */ new Map());
691
+ const processingCodesRef = react.useRef(/* @__PURE__ */ new Set());
678
692
  react.useEffect(() => {
679
693
  const handleMessage = async (event) => {
680
- if (event.origin !== window.location.origin) {
694
+ if (event.origin && event.origin !== window.location.origin) {
681
695
  return;
682
696
  }
683
- if (event.data?.type !== AUTH_CODE_MESSAGE || !event.data.code) {
697
+ const code = typeof event.data?.code === "string" ? event.data.code : "";
698
+ if (event.data?.type !== AUTH_CODE_MESSAGE || !code) {
684
699
  return;
685
700
  }
686
701
  const popupWindow = event.source && "postMessage" in event.source ? event.source : null;
687
702
  const targetSessionId = typeof event.data.sessionId === "string" ? event.data.sessionId : "";
703
+ if (popupWindow && targetSessionId) {
704
+ pendingPopupsRef.current.set(targetSessionId, popupWindow);
705
+ }
688
706
  if (!targetSessionId) {
689
- postPopupResult(popupWindow, {
690
- success: false,
691
- error: "Missing OAuth session identifier"
692
- });
707
+ if (popupWindow) {
708
+ postPopupResult(popupWindow, {
709
+ success: false,
710
+ error: "Missing OAuth session identifier"
711
+ });
712
+ }
693
713
  return;
694
714
  }
695
715
  const targetSession = connections.find((connection) => connection.sessionId === targetSessionId);
696
716
  if (!targetSession) {
697
- postPopupResult(popupWindow, {
698
- sessionId: targetSessionId,
699
- success: false,
700
- error: "OAuth session not found in the current client state"
701
- });
717
+ if (popupWindow) {
718
+ postPopupResult(popupWindow, {
719
+ sessionId: targetSessionId,
720
+ success: false,
721
+ error: "OAuth session not found in the current client state"
722
+ });
723
+ }
702
724
  return;
703
725
  }
704
- if (popupWindow) {
705
- pendingPopupsRef.current.set(targetSession.sessionId, popupWindow);
726
+ const codeKey = `${targetSession.sessionId}:${code}`;
727
+ if (processingCodesRef.current.has(codeKey)) {
728
+ return;
706
729
  }
730
+ processingCodesRef.current.add(codeKey);
707
731
  try {
708
- await finishAuth(targetSession.sessionId, event.data.code);
732
+ await finishAuth(targetSession.sessionId, code);
709
733
  } catch (error) {
734
+ processingCodesRef.current.delete(codeKey);
710
735
  pendingPopupsRef.current.delete(targetSession.sessionId);
711
- postPopupResult(popupWindow, {
712
- sessionId: targetSession.sessionId,
713
- success: false,
714
- error: error instanceof Error ? error.message : "Failed to finish auth"
715
- });
736
+ if (popupWindow) {
737
+ postPopupResult(popupWindow, {
738
+ sessionId: targetSession.sessionId,
739
+ success: false,
740
+ error: error instanceof Error ? error.message : "Failed to finish auth"
741
+ });
742
+ }
743
+ }
744
+ };
745
+ const channel = createAuthBroadcastChannel();
746
+ const handleChannelMessage = (event) => {
747
+ if (event.data?.type === AUTH_CODE_MESSAGE) {
748
+ void handleMessage(event);
716
749
  }
717
750
  };
718
751
  window.addEventListener("message", handleMessage);
719
- return () => window.removeEventListener("message", handleMessage);
752
+ channel?.addEventListener("message", handleChannelMessage);
753
+ return () => {
754
+ window.removeEventListener("message", handleMessage);
755
+ channel?.removeEventListener("message", handleChannelMessage);
756
+ channel?.close();
757
+ };
720
758
  }, [connections, finishAuth]);
721
759
  react.useEffect(() => {
722
760
  for (const connection of connections) {
723
- const popupWindow = pendingPopupsRef.current.get(connection.sessionId);
724
- if (!popupWindow) {
725
- continue;
726
- }
727
- if (connection.state === "AUTHENTICATED") {
761
+ const popupWindow = pendingPopupsRef.current.get(connection.sessionId) || null;
762
+ if (connection.state === "AUTHENTICATED" || connection.state === "READY" || connection.state === "CONNECTED") {
728
763
  postPopupResult(popupWindow, {
729
764
  sessionId: connection.sessionId,
730
765
  success: true
731
766
  });
767
+ for (const codeKey of processingCodesRef.current) {
768
+ if (codeKey.startsWith(`${connection.sessionId}:`)) {
769
+ processingCodesRef.current.delete(codeKey);
770
+ }
771
+ }
732
772
  pendingPopupsRef.current.delete(connection.sessionId);
733
773
  continue;
734
774
  }
@@ -738,6 +778,11 @@ function useMcpOAuthPopup(connections, finishAuth) {
738
778
  success: false,
739
779
  error: connection.error || "Failed to complete authorization"
740
780
  });
781
+ for (const codeKey of processingCodesRef.current) {
782
+ if (codeKey.startsWith(`${connection.sessionId}:`)) {
783
+ processingCodesRef.current.delete(codeKey);
784
+ }
785
+ }
741
786
  pendingPopupsRef.current.delete(connection.sessionId);
742
787
  }
743
788
  }
@@ -758,10 +803,9 @@ function McpOAuthCallbackContent({
758
803
  }) {
759
804
  const [phase, setPhase] = react.useState(debugPhase || "loading");
760
805
  const [errorMessage, setErrorMessage] = react.useState("");
761
- const openerMissing = typeof window !== "undefined" ? !window.opener : false;
762
806
  const missingCode = !code;
763
807
  const missingSessionId = !sessionId;
764
- 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;
808
+ const blockingError = missingCode ? "Error: No authorization code received." : missingSessionId ? "Error: No OAuth state received." : null;
765
809
  react.useEffect(() => {
766
810
  if (debugPhase) {
767
811
  setPhase(debugPhase);
@@ -774,8 +818,9 @@ function McpOAuthCallbackContent({
774
818
  return;
775
819
  }
776
820
  let closed = false;
821
+ const channel = createAuthBroadcastChannel();
777
822
  const handleResult = (event) => {
778
- if (event.origin !== window.location.origin) {
823
+ if (event.origin && event.origin !== window.location.origin) {
779
824
  return;
780
825
  }
781
826
  if (event.data?.type !== AUTH_RESULT_MESSAGE) {
@@ -787,6 +832,7 @@ function McpOAuthCallbackContent({
787
832
  if (event.data.success) {
788
833
  setPhase("success");
789
834
  window.removeEventListener("message", handleResult);
835
+ channel?.close();
790
836
  closed = true;
791
837
  window.setTimeout(() => window.close(), 1200);
792
838
  return;
@@ -796,21 +842,23 @@ function McpOAuthCallbackContent({
796
842
  setErrorMessage(message);
797
843
  };
798
844
  window.addEventListener("message", handleResult);
799
- try {
800
- window.opener.postMessage(
801
- { type: AUTH_CODE_MESSAGE, code, sessionId },
802
- window.location.origin
803
- );
804
- } catch (error) {
805
- console.error("Failed to communicate with opener:", error);
806
- window.setTimeout(() => {
845
+ channel?.addEventListener("message", handleResult);
846
+ const payload = { type: AUTH_CODE_MESSAGE, code, sessionId };
847
+ if (window.opener) {
848
+ try {
849
+ window.opener.postMessage(payload, window.location.origin);
850
+ } catch {
807
851
  setPhase("error");
808
852
  setErrorMessage("Error: Could not communicate with main window.");
809
- }, 0);
853
+ }
854
+ }
855
+ if (channel) {
856
+ channel.postMessage(payload);
810
857
  }
811
858
  return () => {
812
859
  if (!closed) {
813
860
  window.removeEventListener("message", handleResult);
861
+ channel?.close();
814
862
  }
815
863
  };
816
864
  }, [blockingError, code, sessionId, debugPhase]);
@@ -1344,7 +1392,7 @@ var AppHost = class {
1344
1392
  async getSessionId() {
1345
1393
  if (this.sessionId) return this.sessionId;
1346
1394
  if (!this.client) return void 0;
1347
- const result = await this.client.getSessions();
1395
+ const result = await this.client.listSessions();
1348
1396
  return result.sessions?.[0]?.sessionId;
1349
1397
  }
1350
1398
  isMcpUri(url) {