@mcp-ts/sdk 1.5.0 → 1.5.2

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 (66) hide show
  1. package/dist/adapters/agui-adapter.d.mts +1 -1
  2. package/dist/adapters/agui-adapter.d.ts +1 -1
  3. package/dist/adapters/agui-adapter.js +43 -9
  4. package/dist/adapters/agui-adapter.js.map +1 -1
  5. package/dist/adapters/agui-adapter.mjs +43 -9
  6. package/dist/adapters/agui-adapter.mjs.map +1 -1
  7. package/dist/adapters/agui-middleware.d.mts +1 -1
  8. package/dist/adapters/agui-middleware.d.ts +1 -1
  9. package/dist/adapters/agui-middleware.js.map +1 -1
  10. package/dist/adapters/agui-middleware.mjs.map +1 -1
  11. package/dist/adapters/ai-adapter.d.mts +1 -1
  12. package/dist/adapters/ai-adapter.d.ts +1 -1
  13. package/dist/adapters/ai-adapter.js +42 -8
  14. package/dist/adapters/ai-adapter.js.map +1 -1
  15. package/dist/adapters/ai-adapter.mjs +42 -8
  16. package/dist/adapters/ai-adapter.mjs.map +1 -1
  17. package/dist/adapters/langchain-adapter.d.mts +1 -1
  18. package/dist/adapters/langchain-adapter.d.ts +1 -1
  19. package/dist/adapters/langchain-adapter.js +42 -8
  20. package/dist/adapters/langchain-adapter.js.map +1 -1
  21. package/dist/adapters/langchain-adapter.mjs +42 -8
  22. package/dist/adapters/langchain-adapter.mjs.map +1 -1
  23. package/dist/client/react.d.mts +91 -2
  24. package/dist/client/react.d.ts +91 -2
  25. package/dist/client/react.js +339 -3
  26. package/dist/client/react.js.map +1 -1
  27. package/dist/client/react.mjs +335 -4
  28. package/dist/client/react.mjs.map +1 -1
  29. package/dist/client/vue.d.mts +10 -0
  30. package/dist/client/vue.d.ts +10 -0
  31. package/dist/client/vue.js +28 -2
  32. package/dist/client/vue.js.map +1 -1
  33. package/dist/client/vue.mjs +28 -2
  34. package/dist/client/vue.mjs.map +1 -1
  35. package/dist/index.d.mts +1 -1
  36. package/dist/index.d.ts +1 -1
  37. package/dist/index.js +170 -37
  38. package/dist/index.js.map +1 -1
  39. package/dist/index.mjs +170 -37
  40. package/dist/index.mjs.map +1 -1
  41. package/dist/server/index.js +55 -11
  42. package/dist/server/index.js.map +1 -1
  43. package/dist/server/index.mjs +55 -11
  44. package/dist/server/index.mjs.map +1 -1
  45. package/dist/shared/index.d.mts +2 -2
  46. package/dist/shared/index.d.ts +2 -2
  47. package/dist/shared/index.js +115 -26
  48. package/dist/shared/index.js.map +1 -1
  49. package/dist/shared/index.mjs +115 -26
  50. package/dist/shared/index.mjs.map +1 -1
  51. package/dist/{tool-router-XnWVxPzv.d.mts → tool-router-DK0RJblO.d.mts} +3 -0
  52. package/dist/{tool-router-Bo8qZbsD.d.ts → tool-router-DsKhRmJm.d.ts} +3 -0
  53. package/package.json +1 -1
  54. package/src/adapters/agui-adapter.ts +7 -7
  55. package/src/adapters/ai-adapter.ts +5 -5
  56. package/src/adapters/langchain-adapter.ts +5 -5
  57. package/src/client/react/index.ts +14 -0
  58. package/src/client/react/oauth-popup.tsx +446 -0
  59. package/src/client/react/use-mcp.ts +84 -3
  60. package/src/client/vue/use-mcp.ts +80 -3
  61. package/src/server/handlers/sse-handler.ts +39 -0
  62. package/src/server/mcp/oauth-client.ts +32 -14
  63. package/src/shared/meta-tools.ts +62 -13
  64. package/src/shared/tool-index.ts +85 -12
  65. package/src/shared/tool-router.ts +8 -7
  66. package/supabase/migrations/20260421010000_add_session_cleanup_cron.sql +32 -0
@@ -1,7 +1,7 @@
1
1
  import { forwardRef, useRef, useState, useImperativeHandle, useEffect, memo, useCallback, useMemo } from 'react';
2
2
  import { nanoid } from 'nanoid';
3
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
3
4
  import { AppBridge, PostMessageTransport } from '@modelcontextprotocol/ext-apps/app-bridge';
4
- import { jsxs, jsx } from 'react/jsx-runtime';
5
5
 
6
6
  var __defProp = Object.defineProperty;
7
7
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
@@ -313,12 +313,19 @@ function useMcp(options) {
313
313
  const updateConnectionsFromEvent = useCallback((event) => {
314
314
  if (!isMountedRef.current) return;
315
315
  const isTransientReconnectState = (state) => state === "INITIALIZING" || state === "VALIDATING" || state === "RECONNECTING" || state === "CONNECTING" || state === "CONNECTED" || state === "DISCOVERING";
316
+ const getVisibleState = (incomingState, existingState, previousState) => {
317
+ if (incomingState === "INITIALIZING" && (existingState === "AUTHENTICATING" || existingState === "AUTHENTICATED" || previousState === "AUTHENTICATING" || previousState === "AUTHENTICATED")) {
318
+ return existingState === "AUTHENTICATED" || previousState === "AUTHENTICATED" ? "AUTHENTICATED" : "AUTHENTICATING";
319
+ }
320
+ return incomingState;
321
+ };
316
322
  setConnections((prev) => {
317
323
  switch (event.type) {
318
324
  case "state_changed": {
319
325
  const existing = prev.find((c) => c.sessionId === event.sessionId);
320
326
  if (existing) {
321
- const nextState = existing.state === "READY" && isTransientReconnectState(event.state) ? existing.state : event.state;
327
+ const normalizedState = getVisibleState(event.state, existing.state, event.previousState);
328
+ const nextState = existing.state === "READY" && isTransientReconnectState(normalizedState) ? existing.state : normalizedState;
322
329
  return prev.map(
323
330
  (c) => c.sessionId === event.sessionId ? {
324
331
  ...c,
@@ -338,7 +345,9 @@ function useMcp(options) {
338
345
  serverId: event.serverId,
339
346
  serverName: event.serverName,
340
347
  serverUrl: event.serverUrl,
341
- state: event.state,
348
+ // New connections do not have prior local state, so we normalize
349
+ // only against the server-reported previous state.
350
+ state: getVisibleState(event.state, void 0, event.previousState),
342
351
  createdAt: event.createdAt ? new Date(event.createdAt) : void 0,
343
352
  tools: []
344
353
  }
@@ -447,6 +456,27 @@ function useMcp(options) {
447
456
  },
448
457
  []
449
458
  );
459
+ const reconnect = useCallback(
460
+ async (params) => {
461
+ if (!clientRef.current) {
462
+ throw new Error("SSE client not initialized");
463
+ }
464
+ const existing = connections.find(
465
+ (c) => c.serverId === params.serverId || c.serverUrl === params.serverUrl
466
+ );
467
+ if (existing) {
468
+ await clientRef.current.disconnectFromServer(existing.sessionId);
469
+ if (isMountedRef.current) {
470
+ setConnections(
471
+ (prev) => prev.filter((c) => c.sessionId !== existing.sessionId)
472
+ );
473
+ }
474
+ }
475
+ const result = await clientRef.current.connectToServer(params);
476
+ return result.sessionId;
477
+ },
478
+ [connections]
479
+ );
450
480
  const disconnect = useCallback(async (sessionId) => {
451
481
  if (!clientRef.current) {
452
482
  throw new Error("SSE client not initialized");
@@ -548,6 +578,7 @@ function useMcp(options) {
548
578
  status,
549
579
  isInitializing,
550
580
  connect,
581
+ reconnect,
551
582
  disconnect,
552
583
  getConnection,
553
584
  getConnectionByServerId,
@@ -571,6 +602,7 @@ function useMcp(options) {
571
602
  status,
572
603
  isInitializing,
573
604
  connect,
605
+ reconnect,
574
606
  disconnect,
575
607
  getConnection,
576
608
  getConnectionByServerId,
@@ -591,6 +623,305 @@ function useMcp(options) {
591
623
  ]
592
624
  );
593
625
  }
626
+ var AUTH_CODE_MESSAGE = "MCP_AUTH_CODE";
627
+ var AUTH_RESULT_MESSAGE = "MCP_AUTH_RESULT";
628
+ function postPopupResult(popupWindow, result) {
629
+ popupWindow?.postMessage(
630
+ {
631
+ type: AUTH_RESULT_MESSAGE,
632
+ ...result
633
+ },
634
+ window.location.origin
635
+ );
636
+ }
637
+ function openCenteredPopup(url, options = {}) {
638
+ const {
639
+ width = 600,
640
+ height = 700,
641
+ windowName = "mcp-auth-popup",
642
+ features = [],
643
+ onBlocked
644
+ } = options;
645
+ const left = window.screenX + (window.outerWidth - width) / 2;
646
+ const top = window.screenY + (window.outerHeight - height) / 2;
647
+ const featureList = [
648
+ `width=${width}`,
649
+ `height=${height}`,
650
+ `left=${left}`,
651
+ `top=${top}`,
652
+ "resizable=yes",
653
+ "scrollbars=yes",
654
+ "status=yes",
655
+ ...features
656
+ ].join(",");
657
+ const popup = window.open(url, windowName, featureList);
658
+ if (!popup) {
659
+ onBlocked?.(url);
660
+ }
661
+ return popup;
662
+ }
663
+ function createOAuthPopupRedirectHandler(options = {}) {
664
+ return (url) => {
665
+ openCenteredPopup(url, {
666
+ ...options,
667
+ onBlocked: options.onBlocked ?? ((blockedUrl) => {
668
+ window.alert("Popup blocked! Allow popups for this site to complete authentication.");
669
+ window.location.href = blockedUrl;
670
+ })
671
+ });
672
+ };
673
+ }
674
+ function useMcpOAuthPopup(connections, finishAuth) {
675
+ const pendingPopupsRef = useRef(/* @__PURE__ */ new Map());
676
+ useEffect(() => {
677
+ const handleMessage = async (event) => {
678
+ if (event.origin !== window.location.origin) {
679
+ return;
680
+ }
681
+ if (event.data?.type !== AUTH_CODE_MESSAGE || !event.data.code) {
682
+ return;
683
+ }
684
+ const popupWindow = event.source && "postMessage" in event.source ? event.source : null;
685
+ const targetSessionId = typeof event.data.sessionId === "string" ? event.data.sessionId : "";
686
+ if (!targetSessionId) {
687
+ postPopupResult(popupWindow, {
688
+ success: false,
689
+ error: "Missing OAuth session identifier"
690
+ });
691
+ return;
692
+ }
693
+ const targetSession = connections.find((connection) => connection.sessionId === targetSessionId);
694
+ if (!targetSession) {
695
+ postPopupResult(popupWindow, {
696
+ sessionId: targetSessionId,
697
+ success: false,
698
+ error: "OAuth session not found in the current client state"
699
+ });
700
+ return;
701
+ }
702
+ if (popupWindow) {
703
+ pendingPopupsRef.current.set(targetSession.sessionId, popupWindow);
704
+ }
705
+ try {
706
+ await finishAuth(targetSession.sessionId, event.data.code);
707
+ } catch (error) {
708
+ 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
+ });
714
+ }
715
+ };
716
+ window.addEventListener("message", handleMessage);
717
+ return () => window.removeEventListener("message", handleMessage);
718
+ }, [connections, finishAuth]);
719
+ useEffect(() => {
720
+ for (const connection of connections) {
721
+ const popupWindow = pendingPopupsRef.current.get(connection.sessionId);
722
+ if (!popupWindow) {
723
+ continue;
724
+ }
725
+ if (connection.state === "AUTHENTICATED") {
726
+ postPopupResult(popupWindow, {
727
+ sessionId: connection.sessionId,
728
+ success: true
729
+ });
730
+ pendingPopupsRef.current.delete(connection.sessionId);
731
+ continue;
732
+ }
733
+ if (connection.state === "FAILED") {
734
+ postPopupResult(popupWindow, {
735
+ sessionId: connection.sessionId,
736
+ success: false,
737
+ error: connection.error || "Failed to complete authorization"
738
+ });
739
+ pendingPopupsRef.current.delete(connection.sessionId);
740
+ }
741
+ }
742
+ }, [connections]);
743
+ }
744
+ function McpOAuthCallbackContent({
745
+ code,
746
+ sessionId,
747
+ title = "Verifying Authorization",
748
+ initialStatus = "Completing your authorization...",
749
+ loadingFallback = "Loading...",
750
+ rootStyle,
751
+ cardStyle,
752
+ titleStyle,
753
+ messageStyle,
754
+ renderContainer,
755
+ debugPhase
756
+ }) {
757
+ const [phase, setPhase] = useState(debugPhase || "loading");
758
+ const [errorMessage, setErrorMessage] = useState("");
759
+ const openerMissing = typeof window !== "undefined" ? !window.opener : false;
760
+ const missingCode = !code;
761
+ 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;
763
+ useEffect(() => {
764
+ if (debugPhase) {
765
+ setPhase(debugPhase);
766
+ if (debugPhase === "error") setErrorMessage("Test error message representing a real failure.");
767
+ return;
768
+ }
769
+ if (blockingError) {
770
+ setPhase("error");
771
+ setErrorMessage(blockingError);
772
+ return;
773
+ }
774
+ let closed = false;
775
+ const handleResult = (event) => {
776
+ if (event.origin !== window.location.origin) {
777
+ return;
778
+ }
779
+ if (event.data?.type !== AUTH_RESULT_MESSAGE) {
780
+ return;
781
+ }
782
+ if (event.data.sessionId !== sessionId) {
783
+ return;
784
+ }
785
+ if (event.data.success) {
786
+ setPhase("success");
787
+ window.removeEventListener("message", handleResult);
788
+ closed = true;
789
+ window.setTimeout(() => window.close(), 1200);
790
+ return;
791
+ }
792
+ const message = typeof event.data.error === "string" && event.data.error.length > 0 ? event.data.error : "Failed to complete authorization.";
793
+ setPhase("error");
794
+ setErrorMessage(message);
795
+ };
796
+ 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(() => {
805
+ setPhase("error");
806
+ setErrorMessage("Error: Could not communicate with main window.");
807
+ }, 0);
808
+ }
809
+ return () => {
810
+ if (!closed) {
811
+ window.removeEventListener("message", handleResult);
812
+ }
813
+ };
814
+ }, [blockingError, code, sessionId, debugPhase]);
815
+ const loadingBubbles = /* @__PURE__ */ jsx("div", { style: { display: "flex", gap: "8px", justifyContent: "center", height: "12px", alignItems: "center" }, children: [0, 150, 300].map((delay) => /* @__PURE__ */ jsx(
816
+ "span",
817
+ {
818
+ style: {
819
+ width: "8px",
820
+ height: "8px",
821
+ borderRadius: "50%",
822
+ backgroundColor: "currentColor",
823
+ opacity: 0.3,
824
+ animation: `mcp-pulse 1.2s ease-in-out infinite`,
825
+ animationDelay: `${delay}ms`
826
+ }
827
+ },
828
+ delay
829
+ )) });
830
+ const content = /* @__PURE__ */ jsxs(
831
+ "div",
832
+ {
833
+ style: {
834
+ display: "flex",
835
+ justifyContent: "center",
836
+ alignItems: "center",
837
+ minHeight: "100vh",
838
+ fontFamily: "system-ui, -apple-system, sans-serif",
839
+ flexDirection: "column",
840
+ backgroundColor: "#fafafa",
841
+ color: "#18181b",
842
+ boxSizing: "border-box",
843
+ padding: "1.5rem",
844
+ ...rootStyle
845
+ },
846
+ children: [
847
+ /* @__PURE__ */ jsx("style", { children: `
848
+ @keyframes mcp-pulse { 0%, 100% { transform: scale(0.8); opacity: 0.4; } 50% { transform: scale(1.2); opacity: 1; } }
849
+ @keyframes mcp-fade-up { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }
850
+ ` }),
851
+ /* @__PURE__ */ jsx(
852
+ "div",
853
+ {
854
+ style: {
855
+ backgroundColor: "#fff",
856
+ borderRadius: "20px",
857
+ boxShadow: "0 20px 25px -5px rgba(0, 0, 0, 0.05), 0 8px 10px -6px rgba(0, 0, 0, 0.05)",
858
+ width: "100%",
859
+ maxWidth: "400px",
860
+ overflow: "hidden",
861
+ border: "1px solid #f4f4f5",
862
+ display: "flex",
863
+ flexDirection: "column",
864
+ ...cardStyle
865
+ },
866
+ children: /* @__PURE__ */ jsxs("div", { style: { padding: "3rem 2rem", textAlign: "center", animation: "mcp-fade-up 0.4s ease-out" }, children: [
867
+ phase === "loading" && /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "1.5rem", alignItems: "center" }, children: [
868
+ /* @__PURE__ */ jsx("div", { style: { display: "flex", alignItems: "center", justifyContent: "center", height: "48px", width: "48px", background: "#f8fafc", borderRadius: "12px", border: "1px solid #f1f5f9", color: "#64748b" }, children: /* @__PURE__ */ jsx("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" }) }) }),
869
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: [
870
+ /* @__PURE__ */ jsx("h2", { style: { margin: 0, fontSize: "1.125rem", fontWeight: 600, ...titleStyle }, children: title }),
871
+ /* @__PURE__ */ jsx("p", { style: { margin: 0, fontSize: "0.9rem", color: "#71717a", lineHeight: 1.5, ...messageStyle }, children: initialStatus })
872
+ ] }),
873
+ loadingBubbles
874
+ ] }),
875
+ phase === "success" && /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "1rem", alignItems: "center" }, children: [
876
+ /* @__PURE__ */ jsxs("svg", { style: { color: "#10b981" }, width: "48", height: "48", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: [
877
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10" }),
878
+ /* @__PURE__ */ jsx("path", { d: "M8 12l3 3 5-5" })
879
+ ] }),
880
+ /* @__PURE__ */ jsx("h2", { style: { margin: 0, fontSize: "1.25rem", fontWeight: 600, ...titleStyle }, children: "Connected" }),
881
+ /* @__PURE__ */ jsx("p", { style: { margin: 0, fontSize: "0.9rem", color: "#71717a", lineHeight: 1.5, ...messageStyle }, children: "Authorization complete. This window will close automatically." })
882
+ ] }),
883
+ phase === "error" && /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "1rem", alignItems: "center" }, children: [
884
+ /* @__PURE__ */ jsxs("svg", { style: { color: "#ef4444" }, width: "48", height: "48", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: [
885
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10" }),
886
+ /* @__PURE__ */ jsx("path", { d: "M15 9l-6 6M9 9l6 6" })
887
+ ] }),
888
+ /* @__PURE__ */ jsx("h2", { style: { margin: 0, fontSize: "1.25rem", fontWeight: 600, ...titleStyle }, children: "Connection Failed" }),
889
+ /* @__PURE__ */ jsx("p", { style: { margin: 0, fontSize: "0.9rem", color: "#ef4444", fontWeight: 500, ...messageStyle }, children: errorMessage }),
890
+ /* @__PURE__ */ jsx(
891
+ "button",
892
+ {
893
+ onClick: () => window.close(),
894
+ style: {
895
+ marginTop: "0.5rem",
896
+ padding: "0.625rem 1.25rem",
897
+ border: "none",
898
+ borderRadius: "8px",
899
+ backgroundColor: "#fef2f2",
900
+ color: "#ef4444",
901
+ cursor: "pointer",
902
+ fontWeight: 600,
903
+ fontSize: "0.875rem"
904
+ },
905
+ children: "Close Window"
906
+ }
907
+ )
908
+ ] })
909
+ ] })
910
+ }
911
+ )
912
+ ]
913
+ }
914
+ );
915
+ if (renderContainer) {
916
+ return /* @__PURE__ */ jsx(Fragment, { children: renderContainer(content) });
917
+ }
918
+ return content;
919
+ }
920
+ function McpOAuthCallbackFallback({
921
+ children = "Loading..."
922
+ }) {
923
+ return /* @__PURE__ */ jsx(Fragment, { children: children || "Loading..." });
924
+ }
594
925
 
595
926
  // src/client/core/constants.ts
596
927
  var SANDBOX_PROXY_READY_METHOD = "ui/notifications/sandbox-proxy-ready";
@@ -1367,6 +1698,6 @@ function getMcpAppMetadata(mcpClient, toolName, input) {
1367
1698
  return void 0;
1368
1699
  }
1369
1700
 
1370
- export { APP_HOST_DEFAULTS, AppHost, DEFAULT_MCP_APP_CSP, McpAppRenderer, SANDBOX_PROXY_READY_METHOD, SANDBOX_RESOURCE_READY_METHOD, SSEClient, getMcpAppMetadata, useAppHost, useMcp, useMcpApps };
1701
+ export { APP_HOST_DEFAULTS, AppHost, DEFAULT_MCP_APP_CSP, McpAppRenderer, McpOAuthCallbackContent, McpOAuthCallbackFallback, SANDBOX_PROXY_READY_METHOD, SANDBOX_RESOURCE_READY_METHOD, SSEClient, createOAuthPopupRedirectHandler, getMcpAppMetadata, openCenteredPopup, useAppHost, useMcp, useMcpApps, useMcpOAuthPopup };
1371
1702
  //# sourceMappingURL=react.mjs.map
1372
1703
  //# sourceMappingURL=react.mjs.map