@assistant-ui/react-mcp 0.1.19 → 0.1.20

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 (170) hide show
  1. package/dist/auth/buildHeaders.d.ts +2 -4
  2. package/dist/auth/buildHeaders.d.ts.map +1 -1
  3. package/dist/auth/createOAuthProvider.d.ts +19 -20
  4. package/dist/auth/createOAuthProvider.d.ts.map +1 -1
  5. package/dist/auth/types.d.ts +12 -14
  6. package/dist/auth/types.d.ts.map +1 -1
  7. package/dist/connector.d.ts +1 -3
  8. package/dist/connector.d.ts.map +1 -1
  9. package/dist/context/McpConnectorByIndexProvider.d.ts +2 -4
  10. package/dist/context/McpConnectorByIndexProvider.d.ts.map +1 -1
  11. package/dist/context/McpConnectorByIndexProvider.js +1 -1
  12. package/dist/context/McpCustomServerByIndexProvider.d.ts +2 -4
  13. package/dist/context/McpCustomServerByIndexProvider.d.ts.map +1 -1
  14. package/dist/context/McpCustomServerByIndexProvider.js +1 -1
  15. package/dist/context/McpServerByIdProvider.d.ts +2 -4
  16. package/dist/context/McpServerByIdProvider.d.ts.map +1 -1
  17. package/dist/context/McpServerByIdProvider.js +1 -1
  18. package/dist/hooks/useMcpOAuthCallback.d.ts +9 -11
  19. package/dist/hooks/useMcpOAuthCallback.d.ts.map +1 -1
  20. package/dist/hooks/useMcpOAuthCallback.js +2 -2
  21. package/dist/index.d.ts +19 -18
  22. package/dist/index.d.ts.map +1 -0
  23. package/dist/index.js +4 -4
  24. package/dist/mcp-scope.d.ts +110 -112
  25. package/dist/mcp-scope.d.ts.map +1 -1
  26. package/dist/primitives/addForm/McpAddFormAuthFields.d.ts +12 -14
  27. package/dist/primitives/addForm/McpAddFormAuthFields.d.ts.map +1 -1
  28. package/dist/primitives/addForm/McpAddFormAuthSelect.d.ts +3 -5
  29. package/dist/primitives/addForm/McpAddFormAuthSelect.d.ts.map +1 -1
  30. package/dist/primitives/addForm/McpAddFormAuthSelect.js +1 -1
  31. package/dist/primitives/addForm/McpAddFormBearerTokenField.d.ts +3 -5
  32. package/dist/primitives/addForm/McpAddFormBearerTokenField.d.ts.map +1 -1
  33. package/dist/primitives/addForm/McpAddFormBearerTokenField.js +1 -1
  34. package/dist/primitives/addForm/McpAddFormCancel.d.ts +4 -6
  35. package/dist/primitives/addForm/McpAddFormCancel.d.ts.map +1 -1
  36. package/dist/primitives/addForm/McpAddFormCancel.js +1 -1
  37. package/dist/primitives/addForm/McpAddFormError.d.ts +4 -6
  38. package/dist/primitives/addForm/McpAddFormError.d.ts.map +1 -1
  39. package/dist/primitives/addForm/McpAddFormError.js +1 -1
  40. package/dist/primitives/addForm/McpAddFormNameField.d.ts +3 -5
  41. package/dist/primitives/addForm/McpAddFormNameField.d.ts.map +1 -1
  42. package/dist/primitives/addForm/McpAddFormNameField.js +1 -1
  43. package/dist/primitives/addForm/McpAddFormRoot.d.ts +9 -11
  44. package/dist/primitives/addForm/McpAddFormRoot.d.ts.map +1 -1
  45. package/dist/primitives/addForm/McpAddFormRoot.js +2 -2
  46. package/dist/primitives/addForm/McpAddFormScopesField.d.ts +3 -5
  47. package/dist/primitives/addForm/McpAddFormScopesField.d.ts.map +1 -1
  48. package/dist/primitives/addForm/McpAddFormScopesField.js +1 -1
  49. package/dist/primitives/addForm/McpAddFormSubmit.d.ts +4 -6
  50. package/dist/primitives/addForm/McpAddFormSubmit.d.ts.map +1 -1
  51. package/dist/primitives/addForm/McpAddFormSubmit.js +1 -1
  52. package/dist/primitives/addForm/McpAddFormUrlField.d.ts +3 -5
  53. package/dist/primitives/addForm/McpAddFormUrlField.d.ts.map +1 -1
  54. package/dist/primitives/addForm/McpAddFormUrlField.js +1 -1
  55. package/dist/primitives/addForm/context.d.ts +18 -20
  56. package/dist/primitives/addForm/context.d.ts.map +1 -1
  57. package/dist/primitives/addForm.d.ts +10 -15
  58. package/dist/primitives/addForm.d.ts.map +1 -1
  59. package/dist/primitives/elicitation/McpElicitationPrimitiveAccept.d.ts +4 -6
  60. package/dist/primitives/elicitation/McpElicitationPrimitiveAccept.d.ts.map +1 -1
  61. package/dist/primitives/elicitation/McpElicitationPrimitiveAccept.js +2 -2
  62. package/dist/primitives/elicitation/McpElicitationPrimitiveCancel.d.ts +4 -6
  63. package/dist/primitives/elicitation/McpElicitationPrimitiveCancel.d.ts.map +1 -1
  64. package/dist/primitives/elicitation/McpElicitationPrimitiveCancel.js +2 -2
  65. package/dist/primitives/elicitation/McpElicitationPrimitiveDecline.d.ts +4 -6
  66. package/dist/primitives/elicitation/McpElicitationPrimitiveDecline.d.ts.map +1 -1
  67. package/dist/primitives/elicitation/McpElicitationPrimitiveDecline.js +2 -2
  68. package/dist/primitives/elicitation/McpElicitationPrimitiveError.d.ts +4 -6
  69. package/dist/primitives/elicitation/McpElicitationPrimitiveError.d.ts.map +1 -1
  70. package/dist/primitives/elicitation/McpElicitationPrimitiveError.js +1 -1
  71. package/dist/primitives/elicitation/McpElicitationPrimitiveFields.d.ts +6 -8
  72. package/dist/primitives/elicitation/McpElicitationPrimitiveFields.d.ts.map +1 -1
  73. package/dist/primitives/elicitation/McpElicitationPrimitiveFields.js +1 -1
  74. package/dist/primitives/elicitation/McpElicitationPrimitiveItems.d.ts +6 -9
  75. package/dist/primitives/elicitation/McpElicitationPrimitiveItems.d.ts.map +1 -1
  76. package/dist/primitives/elicitation/McpElicitationPrimitiveItems.js +2 -2
  77. package/dist/primitives/elicitation/McpElicitationPrimitiveMessage.d.ts +4 -6
  78. package/dist/primitives/elicitation/McpElicitationPrimitiveMessage.d.ts.map +1 -1
  79. package/dist/primitives/elicitation/McpElicitationPrimitiveMessage.js +1 -1
  80. package/dist/primitives/elicitation/McpElicitationPrimitiveRoot.d.ts +4 -6
  81. package/dist/primitives/elicitation/McpElicitationPrimitiveRoot.d.ts.map +1 -1
  82. package/dist/primitives/elicitation/McpElicitationPrimitiveRoot.js +1 -1
  83. package/dist/primitives/elicitation/context.d.ts +8 -10
  84. package/dist/primitives/elicitation/context.d.ts.map +1 -1
  85. package/dist/primitives/elicitation/initialElicitationDraft.d.ts +0 -2
  86. package/dist/primitives/elicitation/initialElicitationDraft.d.ts.map +1 -1
  87. package/dist/primitives/elicitation/prepareElicitationContent.d.ts +3 -5
  88. package/dist/primitives/elicitation/prepareElicitationContent.d.ts.map +1 -1
  89. package/dist/primitives/elicitation.d.ts +8 -14
  90. package/dist/primitives/elicitation.d.ts.map +1 -1
  91. package/dist/primitives/manager/McpManagerAddCustomTrigger.d.ts +4 -6
  92. package/dist/primitives/manager/McpManagerAddCustomTrigger.d.ts.map +1 -1
  93. package/dist/primitives/manager/McpManagerAddCustomTrigger.js +1 -1
  94. package/dist/primitives/manager/McpManagerConnectors.d.ts +12 -14
  95. package/dist/primitives/manager/McpManagerConnectors.d.ts.map +1 -1
  96. package/dist/primitives/manager/McpManagerConnectors.js +1 -1
  97. package/dist/primitives/manager/McpManagerCustomServers.d.ts +12 -14
  98. package/dist/primitives/manager/McpManagerCustomServers.d.ts.map +1 -1
  99. package/dist/primitives/manager/McpManagerCustomServers.js +1 -1
  100. package/dist/primitives/manager/McpManagerRoot.d.ts +4 -6
  101. package/dist/primitives/manager/McpManagerRoot.d.ts.map +1 -1
  102. package/dist/primitives/manager/McpManagerRoot.js +2 -2
  103. package/dist/primitives/manager.d.ts +4 -9
  104. package/dist/primitives/manager.d.ts.map +1 -1
  105. package/dist/primitives/server/McpServerConnectButton.d.ts +4 -6
  106. package/dist/primitives/server/McpServerConnectButton.d.ts.map +1 -1
  107. package/dist/primitives/server/McpServerConnectButton.js +2 -2
  108. package/dist/primitives/server/McpServerDisconnectButton.d.ts +4 -6
  109. package/dist/primitives/server/McpServerDisconnectButton.d.ts.map +1 -1
  110. package/dist/primitives/server/McpServerDisconnectButton.js +2 -2
  111. package/dist/primitives/server/McpServerError.d.ts +4 -6
  112. package/dist/primitives/server/McpServerError.d.ts.map +1 -1
  113. package/dist/primitives/server/McpServerError.js +2 -2
  114. package/dist/primitives/server/McpServerIcon.d.ts +11 -13
  115. package/dist/primitives/server/McpServerIcon.d.ts.map +1 -1
  116. package/dist/primitives/server/McpServerIcon.js +2 -2
  117. package/dist/primitives/server/McpServerName.d.ts +4 -6
  118. package/dist/primitives/server/McpServerName.d.ts.map +1 -1
  119. package/dist/primitives/server/McpServerName.js +2 -2
  120. package/dist/primitives/server/McpServerOAuthLink.d.ts +9 -11
  121. package/dist/primitives/server/McpServerOAuthLink.d.ts.map +1 -1
  122. package/dist/primitives/server/McpServerOAuthLink.js +2 -2
  123. package/dist/primitives/server/McpServerRemoveButton.d.ts +4 -6
  124. package/dist/primitives/server/McpServerRemoveButton.d.ts.map +1 -1
  125. package/dist/primitives/server/McpServerRemoveButton.js +2 -2
  126. package/dist/primitives/server/McpServerRoot.d.ts +4 -6
  127. package/dist/primitives/server/McpServerRoot.d.ts.map +1 -1
  128. package/dist/primitives/server/McpServerRoot.js +2 -2
  129. package/dist/primitives/server/McpServerStatus.d.ts +4 -6
  130. package/dist/primitives/server/McpServerStatus.d.ts.map +1 -1
  131. package/dist/primitives/server/McpServerStatus.js +2 -2
  132. package/dist/primitives/server/McpServerToolName.d.ts +4 -6
  133. package/dist/primitives/server/McpServerToolName.d.ts.map +1 -1
  134. package/dist/primitives/server/McpServerToolName.js +1 -1
  135. package/dist/primitives/server/McpServerTools.d.ts +5 -7
  136. package/dist/primitives/server/McpServerTools.d.ts.map +1 -1
  137. package/dist/primitives/server/McpServerTools.js +2 -2
  138. package/dist/primitives/server.d.ts +11 -16
  139. package/dist/primitives/server.d.ts.map +1 -1
  140. package/dist/resources/McpManagerResource.d.ts +11 -13
  141. package/dist/resources/McpManagerResource.d.ts.map +1 -1
  142. package/dist/resources/McpManagerResource.js +2 -2
  143. package/dist/resources/McpServerRemovalFence.d.ts +1 -3
  144. package/dist/resources/McpServerRemovalFence.d.ts.map +1 -1
  145. package/dist/resources/McpServerResource.d.ts +18 -20
  146. package/dist/resources/McpServerResource.d.ts.map +1 -1
  147. package/dist/resources/McpServerResource.js +51 -43
  148. package/dist/resources/McpServerResource.js.map +1 -1
  149. package/dist/resources/storage/McpCustomStorage.d.ts +1 -3
  150. package/dist/resources/storage/McpCustomStorage.d.ts.map +1 -1
  151. package/dist/resources/storage/McpLocalStorage.d.ts +14 -16
  152. package/dist/resources/storage/McpLocalStorage.d.ts.map +1 -1
  153. package/dist/resources/storage/McpLocalStorage.js +1 -1
  154. package/dist/resources/storage/McpMemoryStorage.d.ts +1 -3
  155. package/dist/resources/storage/McpMemoryStorage.d.ts.map +1 -1
  156. package/dist/resources/storage/types.d.ts +22 -24
  157. package/dist/resources/storage/types.d.ts.map +1 -1
  158. package/dist/resources/validateElicitationContent.d.ts +3 -4
  159. package/dist/resources/validateElicitationContent.d.ts.map +1 -1
  160. package/dist/utils/createMcpId.d.ts +0 -2
  161. package/dist/utils/createMcpId.d.ts.map +1 -1
  162. package/dist/utils/invokeMcpCallback.d.ts +0 -2
  163. package/dist/utils/invokeMcpCallback.d.ts.map +1 -1
  164. package/dist/utils/serverId.d.ts +0 -2
  165. package/dist/utils/serverId.d.ts.map +1 -1
  166. package/dist/utils/serverUrl.d.ts +1 -3
  167. package/dist/utils/serverUrl.d.ts.map +1 -1
  168. package/package.json +6 -6
  169. package/src/resources/McpServerResource.test.ts +112 -0
  170. package/src/resources/McpServerResource.ts +22 -7
@@ -1 +1 @@
1
- {"version":3,"file":"invokeMcpCallback.d.ts","names":[],"sources":["../../src/utils/invokeMcpCallback.ts"],"mappings":";qBAEa,oBAAqB,yBAChC,cACA,eAAe,MAAM,gCAClB,MAAM"}
1
+ {"version":3,"file":"invokeMcpCallback.d.ts","sourceRoot":"","sources":["../../src/utils/invokeMcpCallback.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,iBAAiB,GAAI,KAAK,SAAS,OAAO,EAAE,EACvD,MAAM,MAAM,EACZ,UAAU,CAAC,CAAC,GAAG,IAAI,EAAE,KAAK,KAAK,IAAI,CAAC,GAAG,SAAS,EAChD,GAAG,MAAM,KAAK,KACb,IAEF,CAAC"}
@@ -1,5 +1,3 @@
1
- //#region src/utils/serverId.d.ts
2
1
  export declare function assertValidServerId(id: string): void;
3
2
  export declare function assertUniqueServerIds(ids: Iterable<string>): void;
4
- //#endregion
5
3
  //# sourceMappingURL=serverId.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"serverId.d.ts","names":[],"sources":["../../src/utils/serverId.ts"],"mappings":";wBAIgB,oBAAoB;wBAgBpB,sBAAsB,KAAK"}
1
+ {"version":3,"file":"serverId.d.ts","sourceRoot":"","sources":["../../src/utils/serverId.ts"],"names":[],"mappings":"AAIA,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAcpD;AAED,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,IAAI,CAUjE"}
@@ -1,7 +1,5 @@
1
- import { MCPPersistedAuthState } from "../auth/types.js";
2
- //#region src/utils/serverUrl.d.ts
1
+ import type { MCPPersistedAuthState } from "../auth/types.js";
3
2
  export declare const normalizeMcpServerUrl: (serverUrl: string) => string;
4
3
  export declare const isAuthStateForServerUrl: (state: MCPPersistedAuthState | null, serverUrl: string) => boolean;
5
4
  export declare const hasPersistedCredentials: (state: MCPPersistedAuthState | null) => boolean;
6
- //#endregion
7
5
  //# sourceMappingURL=serverUrl.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"serverUrl.d.ts","names":[],"sources":["../../src/utils/serverUrl.ts"],"mappings":";;qBAEa,wBAAyB;qBAGzB,0BACX,OAAO,8BACP;qBAaW,0BACX,OAAO"}
1
+ {"version":3,"file":"serverUrl.d.ts","sourceRoot":"","sources":["../../src/utils/serverUrl.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,yBAAsB;AAE3D,eAAO,MAAM,qBAAqB,GAAI,WAAW,MAAM,KAAG,MAC3B,CAAC;AAEhC,eAAO,MAAM,uBAAuB,GAClC,OAAO,qBAAqB,GAAG,IAAI,EACnC,WAAW,MAAM,KAChB,OAUF,CAAC;AAEF,eAAO,MAAM,uBAAuB,GAClC,OAAO,qBAAqB,GAAG,IAAI,KAClC,OAA0D,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@assistant-ui/react-mcp",
3
- "version": "0.1.19",
3
+ "version": "0.1.20",
4
4
  "description": "MCP server configuration and connection primitives for @assistant-ui",
5
5
  "keywords": [
6
6
  "mcp",
@@ -27,13 +27,13 @@
27
27
  ],
28
28
  "sideEffects": false,
29
29
  "dependencies": {
30
- "@assistant-ui/core": "^0.3.20",
31
- "@assistant-ui/store": "^0.3.14",
32
- "@assistant-ui/tap": "^0.9.18",
30
+ "@assistant-ui/core": "^0.3.21",
31
+ "@assistant-ui/store": "^0.3.15",
32
+ "@assistant-ui/tap": "^0.9.19",
33
33
  "@modelcontextprotocol/client": "^2.0.0",
34
34
  "@modelcontextprotocol/core": "^2.0.0",
35
35
  "@radix-ui/react-primitive": "^2.1.10",
36
- "assistant-stream": "^0.3.44"
36
+ "assistant-stream": "^0.3.45"
37
37
  },
38
38
  "peerDependencies": {
39
39
  "@types/react": "*",
@@ -45,7 +45,7 @@
45
45
  }
46
46
  },
47
47
  "devDependencies": {
48
- "@assistant-ui/x-buildutils": "0.0.28",
48
+ "@assistant-ui/x-buildutils": "0.0.29",
49
49
  "@testing-library/dom": "^10.4.2",
50
50
  "@testing-library/react": "^16.3.3",
51
51
  "@types/react": "^19.3.0",
@@ -1,5 +1,6 @@
1
1
  import { createTapRoot, resource, useResource } from "@assistant-ui/tap";
2
2
  import type { ClientOutput } from "@assistant-ui/store";
3
+ import { UnauthorizedError } from "@modelcontextprotocol/client";
3
4
  import { useEffect, useState } from "react";
4
5
  import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
5
6
  import type { MCPAuthConfig } from "../mcp-scope";
@@ -192,6 +193,15 @@ const mount = (
192
193
  const unboundAuthMessage =
193
194
  'MCP server "docs" has saved authentication for a different URL. Authenticate again to connect to https://example.com/mcp.';
194
195
 
196
+ const getOAuthProvider = (index: number) => {
197
+ const provider =
198
+ mocks.StreamableHTTPClientTransport.mock.calls[index]?.[1]?.authProvider;
199
+ if (!provider) throw new Error("Expected OAuth provider");
200
+ return provider as {
201
+ redirectToAuthorization: (url: URL) => Promise<void>;
202
+ };
203
+ };
204
+
195
205
  describe("McpServerResource automatic authentication", () => {
196
206
  beforeEach(resetMocks);
197
207
 
@@ -632,6 +642,70 @@ describe("McpServerResource connectionTimeout", () => {
632
642
  describe("McpServerResource connection lifecycle", () => {
633
643
  beforeEach(resetMocks);
634
644
 
645
+ it("publishes authorization URLs from the current connection", async () => {
646
+ const root = mount({ auth: { type: "oauth" } });
647
+
648
+ try {
649
+ await root.getValue().connect();
650
+ await getOAuthProvider(0).redirectToAuthorization(
651
+ new URL("https://auth.example.com/current"),
652
+ );
653
+ await waitForResourceUpdate(
654
+ () => root.getValue().getState().authorizationUrl !== null,
655
+ );
656
+
657
+ expect(root.getValue().getState().authorizationUrl).toBe(
658
+ "https://auth.example.com/current",
659
+ );
660
+ } finally {
661
+ root.unmount();
662
+ }
663
+ });
664
+
665
+ it("ignores authorization URLs after disconnect", async () => {
666
+ const root = mount({ auth: { type: "oauth" } });
667
+
668
+ try {
669
+ await root.getValue().connect();
670
+ const provider = getOAuthProvider(0);
671
+ await root.getValue().disconnect();
672
+
673
+ await provider.redirectToAuthorization(
674
+ new URL("https://auth.example.com/stale"),
675
+ );
676
+ await flushMacrotask();
677
+
678
+ expect(root.getValue().getState()).toMatchObject({
679
+ connectionState: "disconnected",
680
+ authorizationUrl: null,
681
+ });
682
+ } finally {
683
+ root.unmount();
684
+ }
685
+ });
686
+
687
+ it("ignores authorization URLs from a superseded connection", async () => {
688
+ const root = mount({ auth: { type: "oauth" } });
689
+
690
+ try {
691
+ await root.getValue().connect();
692
+ const staleProvider = getOAuthProvider(0);
693
+ await root.getValue().connect();
694
+
695
+ await staleProvider.redirectToAuthorization(
696
+ new URL("https://auth.example.com/stale"),
697
+ );
698
+ await flushMacrotask();
699
+
700
+ expect(root.getValue().getState()).toMatchObject({
701
+ connectionState: "connected",
702
+ authorizationUrl: null,
703
+ });
704
+ } finally {
705
+ root.unmount();
706
+ }
707
+ });
708
+
635
709
  it("replaces direct resource connections when the server id changes", async () => {
636
710
  const storage = createStorage();
637
711
  let updateId = (_id: string) => {};
@@ -747,6 +821,44 @@ describe("McpServerResource connection lifecycle", () => {
747
821
  describe("McpServerResource completeAuth", () => {
748
822
  beforeEach(resetMocks);
749
823
 
824
+ it("transfers authorization URL ownership when reusing the auth transport", async () => {
825
+ const storage = createStorage();
826
+ vi.mocked(storage.loadAuthState).mockResolvedValue({
827
+ serverUrl: "https://example.com/mcp",
828
+ state: "expected",
829
+ });
830
+ mocks.connectResults.push(() =>
831
+ Promise.reject(new UnauthorizedError("authorization required")),
832
+ );
833
+ const root = mount({ auth: { type: "oauth" }, storage });
834
+
835
+ try {
836
+ await root.getValue().connect();
837
+ await waitForResourceUpdate(
838
+ () => root.getValue().getState().connectionState === "authRequired",
839
+ );
840
+ const provider = getOAuthProvider(0);
841
+
842
+ await root
843
+ .getValue()
844
+ .completeAuth("https://example.com/callback?code=abc&state=expected");
845
+ await provider.redirectToAuthorization(
846
+ new URL("https://auth.example.com/reauthorize"),
847
+ );
848
+ await waitForResourceUpdate(
849
+ () => root.getValue().getState().authorizationUrl !== null,
850
+ );
851
+
852
+ expect(root.getValue().getState()).toMatchObject({
853
+ connectionState: "connected",
854
+ authorizationUrl: "https://auth.example.com/reauthorize",
855
+ });
856
+ expect(mocks.transports).toHaveLength(1);
857
+ } finally {
858
+ root.unmount();
859
+ }
860
+ });
861
+
750
862
  it("lets callback validation win over mount-time auto-connect", async () => {
751
863
  const pendingLoads: Array<(value: MCPPersistedAuthState | null) => void> =
752
864
  [];
@@ -105,6 +105,9 @@ const useMcpServerResourceInstance = (
105
105
  const pendingTransportRef = useRef<StreamableHTTPClientTransport | null>(
106
106
  null,
107
107
  );
108
+ const transportGenerationRef = useRef(
109
+ new WeakMap<StreamableHTTPClientTransport, { current: number }>(),
110
+ );
108
111
  const connectionGenerationRef = useRef(0);
109
112
  const pendingAuthValidationRef = useRef<{
110
113
  count: number;
@@ -254,19 +257,29 @@ const useMcpServerResourceInstance = (
254
257
  });
255
258
 
256
259
  const buildTransport = useEffectEvent(
257
- async (): Promise<StreamableHTTPClientTransport> => {
260
+ async (generation: number): Promise<StreamableHTTPClientTransport> => {
258
261
  if (props.auth.type === "oauth") {
262
+ const generationOwner = { current: generation };
259
263
  const authProvider = createOAuthProvider({
260
264
  serverId: props.id,
261
265
  serverUrl: props.url,
262
266
  config: props.auth,
263
267
  storage: props.storage,
264
268
  redirectUri: props.redirectUri,
265
- onAuthorizationUrl: (url) => setAuthorizationUrl(url.toString()),
266
- });
267
- return new StreamableHTTPClientTransport(new URL(props.url), {
268
- authProvider,
269
+ onAuthorizationUrl: (url) => {
270
+ if (isCurrentConnection(generationOwner.current)) {
271
+ setAuthorizationUrl(url.toString());
272
+ }
273
+ },
269
274
  });
275
+ const transport = new StreamableHTTPClientTransport(
276
+ new URL(props.url),
277
+ {
278
+ authProvider,
279
+ },
280
+ );
281
+ transportGenerationRef.current.set(transport, generationOwner);
282
+ return transport;
270
283
  }
271
284
  if (props.auth.type === "bearer") {
272
285
  const { state, unbound } = await loadAuthState();
@@ -443,7 +456,7 @@ const useMcpServerResourceInstance = (
443
456
  setTools([]);
444
457
  let transport: StreamableHTTPClientTransport | null = null;
445
458
  try {
446
- transport = await buildTransport();
459
+ transport = await buildTransport(generation);
447
460
  if (!isCurrentConnection(generation)) {
448
461
  await closeQueuedTransports([transport]);
449
462
  return;
@@ -536,12 +549,14 @@ const useMcpServerResourceInstance = (
536
549
  try {
537
550
  let transport = transportRef.current;
538
551
  if (!transport) {
539
- transport = await buildTransport();
552
+ transport = await buildTransport(generation);
540
553
  if (!isCurrentConnection(generation)) {
541
554
  await closeQueuedTransports([transport]);
542
555
  throw createInterruptedAuthError();
543
556
  }
544
557
  }
558
+ const generationOwner = transportGenerationRef.current.get(transport);
559
+ if (generationOwner) generationOwner.current = generation;
545
560
  transportRef.current = null;
546
561
  clientRef.current = null;
547
562
  pendingTransportRef.current = transport;