@assistant-ui/react-mcp 0.1.16 → 0.1.18
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/auth/createOAuthProvider.d.ts +13 -2
- package/dist/auth/createOAuthProvider.d.ts.map +1 -1
- package/dist/auth/createOAuthProvider.js +109 -31
- package/dist/auth/createOAuthProvider.js.map +1 -1
- package/dist/auth/types.d.ts +5 -1
- package/dist/auth/types.d.ts.map +1 -1
- package/dist/primitives/addForm/McpAddFormAuthFields.js +71 -28
- package/dist/primitives/addForm/McpAddFormAuthFields.js.map +1 -1
- package/dist/primitives/addForm/McpAddFormError.d.ts.map +1 -1
- package/dist/primitives/addForm/McpAddFormError.js +30 -10
- package/dist/primitives/addForm/McpAddFormError.js.map +1 -1
- package/dist/primitives/addForm/McpAddFormNameField.js +31 -18
- package/dist/primitives/addForm/McpAddFormNameField.js.map +1 -1
- package/dist/primitives/addForm/McpAddFormRoot.d.ts.map +1 -1
- package/dist/primitives/addForm/McpAddFormRoot.js +32 -11
- package/dist/primitives/addForm/McpAddFormRoot.js.map +1 -1
- package/dist/primitives/addForm/McpAddFormUrlField.js +31 -18
- package/dist/primitives/addForm/McpAddFormUrlField.js.map +1 -1
- package/dist/primitives/addForm/context.d.ts +9 -1
- package/dist/primitives/addForm/context.d.ts.map +1 -1
- package/dist/primitives/addForm/context.js.map +1 -1
- package/dist/resources/McpManagerResource.d.ts.map +1 -1
- package/dist/resources/McpManagerResource.js +330 -247
- package/dist/resources/McpManagerResource.js.map +1 -1
- package/dist/resources/McpServerRemovalFence.d.ts +7 -0
- package/dist/resources/McpServerRemovalFence.d.ts.map +1 -0
- package/dist/resources/McpServerRemovalFence.js +11 -0
- package/dist/resources/McpServerRemovalFence.js.map +1 -0
- package/dist/resources/McpServerResource.d.ts.map +1 -1
- package/dist/resources/McpServerResource.js +41 -16
- package/dist/resources/McpServerResource.js.map +1 -1
- package/dist/resources/storage/McpLocalStorage.d.ts.map +1 -1
- package/dist/resources/storage/McpLocalStorage.js +16 -1
- package/dist/resources/storage/McpLocalStorage.js.map +1 -1
- package/dist/resources/storage/types.d.ts +10 -8
- package/dist/resources/storage/types.d.ts.map +1 -1
- package/dist/utils/serverUrl.d.ts +8 -0
- package/dist/utils/serverUrl.d.ts.map +1 -0
- package/dist/utils/serverUrl.js +15 -0
- package/dist/utils/serverUrl.js.map +1 -0
- package/package.json +7 -7
- package/src/auth/createOAuthProvider.test.ts +544 -35
- package/src/auth/createOAuthProvider.ts +201 -46
- package/src/auth/types.ts +5 -1
- package/src/primitives/addForm/McpAddFormAccessibility.test.tsx +261 -0
- package/src/primitives/addForm/McpAddFormAuthFields.tsx +33 -15
- package/src/primitives/addForm/McpAddFormError.tsx +17 -3
- package/src/primitives/addForm/McpAddFormNameField.tsx +13 -1
- package/src/primitives/addForm/McpAddFormRoot.tsx +51 -8
- package/src/primitives/addForm/McpAddFormUrlField.tsx +12 -1
- package/src/primitives/addForm/context.tsx +10 -0
- package/src/resources/McpManagerResource.test.ts +712 -9
- package/src/resources/McpManagerResource.ts +208 -56
- package/src/resources/McpServerRemovalFence.ts +21 -0
- package/src/resources/McpServerResource.test.ts +252 -17
- package/src/resources/McpServerResource.ts +40 -15
- package/src/resources/storage/McpLocalStorage.test.ts +28 -0
- package/src/resources/storage/McpLocalStorage.ts +23 -1
- package/src/resources/storage/types.ts +10 -8
- package/src/utils/serverUrl.test.ts +66 -0
- package/src/utils/serverUrl.ts +23 -0
|
@@ -5,14 +5,16 @@ import type { MCPPersistedAuthState } from "../../auth/types";
|
|
|
5
5
|
export type MCPStorage = {
|
|
6
6
|
/**
|
|
7
7
|
* Stable identity of the backing store. Two storages with the same scopeId
|
|
8
|
-
* must read and write the same persisted data. When present,
|
|
9
|
-
* connections and the OAuth write fence key on it
|
|
10
|
-
* differently-scoped storage
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
8
|
+
* must read and write the same persisted data. When present, custom servers,
|
|
9
|
+
* server connections, and the OAuth write fence key on it. Swapping to a
|
|
10
|
+
* differently-scoped storage rehydrates its custom servers and reconnects
|
|
11
|
+
* authenticated servers instead of retaining data or a live OAuth flow from
|
|
12
|
+
* the replaced store. Clearing through a same-scoped replacement still waits
|
|
13
|
+
* for writes queued against the storage it replaced. When absent, the fence
|
|
14
|
+
* falls back to object identity while custom servers and connections never
|
|
15
|
+
* re-key. Replacing an unscoped storage can therefore persist the previous
|
|
16
|
+
* store's custom servers into the replacement, and a clear runs unfenced
|
|
17
|
+
* against writes queued by the object it replaced.
|
|
16
18
|
*/
|
|
17
19
|
scopeId?: string;
|
|
18
20
|
loadCustomServers: () => Promise<MCPCustomServerRecord[]>;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import {
|
|
3
|
+
hasPersistedCredentials,
|
|
4
|
+
isAuthStateForServerUrl,
|
|
5
|
+
normalizeMcpServerUrl,
|
|
6
|
+
} from "./serverUrl";
|
|
7
|
+
|
|
8
|
+
describe("normalizeMcpServerUrl", () => {
|
|
9
|
+
it("normalizes host case and the default port", () => {
|
|
10
|
+
expect(normalizeMcpServerUrl("https://MCP.Example.com:443/mcp")).toBe(
|
|
11
|
+
"https://mcp.example.com/mcp",
|
|
12
|
+
);
|
|
13
|
+
});
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
describe("isAuthStateForServerUrl", () => {
|
|
17
|
+
it("matches equivalent spellings of the same endpoint", () => {
|
|
18
|
+
expect(
|
|
19
|
+
isAuthStateForServerUrl(
|
|
20
|
+
{ serverUrl: "https://MCP.Example.com/mcp" },
|
|
21
|
+
"https://mcp.example.com:443/mcp",
|
|
22
|
+
),
|
|
23
|
+
).toBe(true);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it("rejects a different endpoint, an unbound record, and no record", () => {
|
|
27
|
+
expect(
|
|
28
|
+
isAuthStateForServerUrl(
|
|
29
|
+
{ serverUrl: "https://a.example.com/mcp" },
|
|
30
|
+
"https://b.example.com/mcp",
|
|
31
|
+
),
|
|
32
|
+
).toBe(false);
|
|
33
|
+
expect(
|
|
34
|
+
isAuthStateForServerUrl({ token: "t" }, "https://a.example.com/mcp"),
|
|
35
|
+
).toBe(false);
|
|
36
|
+
expect(isAuthStateForServerUrl(null, "https://a.example.com/mcp")).toBe(
|
|
37
|
+
false,
|
|
38
|
+
);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it("rejects an unparsable URL on either side", () => {
|
|
42
|
+
expect(
|
|
43
|
+
isAuthStateForServerUrl({ serverUrl: "not a url" }, "https://a.test/mcp"),
|
|
44
|
+
).toBe(false);
|
|
45
|
+
expect(
|
|
46
|
+
isAuthStateForServerUrl({ serverUrl: "https://a.test/mcp" }, "not a url"),
|
|
47
|
+
).toBe(false);
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
describe("hasPersistedCredentials", () => {
|
|
52
|
+
it("counts bearer and OAuth tokens, not flow state", () => {
|
|
53
|
+
expect(hasPersistedCredentials({ token: "t" })).toBe(true);
|
|
54
|
+
expect(hasPersistedCredentials({ token: "" })).toBe(false);
|
|
55
|
+
expect(
|
|
56
|
+
hasPersistedCredentials({
|
|
57
|
+
tokens: { access_token: "a", token_type: "bearer" },
|
|
58
|
+
}),
|
|
59
|
+
).toBe(true);
|
|
60
|
+
expect(hasPersistedCredentials({ codeVerifier: "v", state: "s" })).toBe(
|
|
61
|
+
false,
|
|
62
|
+
);
|
|
63
|
+
expect(hasPersistedCredentials({})).toBe(false);
|
|
64
|
+
expect(hasPersistedCredentials(null)).toBe(false);
|
|
65
|
+
});
|
|
66
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { MCPPersistedAuthState } from "../auth/types";
|
|
2
|
+
|
|
3
|
+
export const normalizeMcpServerUrl = (serverUrl: string): string =>
|
|
4
|
+
new URL(serverUrl).toString();
|
|
5
|
+
|
|
6
|
+
export const isAuthStateForServerUrl = (
|
|
7
|
+
state: MCPPersistedAuthState | null,
|
|
8
|
+
serverUrl: string,
|
|
9
|
+
): boolean => {
|
|
10
|
+
if (state?.serverUrl === undefined) return false;
|
|
11
|
+
try {
|
|
12
|
+
return (
|
|
13
|
+
normalizeMcpServerUrl(state.serverUrl) ===
|
|
14
|
+
normalizeMcpServerUrl(serverUrl)
|
|
15
|
+
);
|
|
16
|
+
} catch {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export const hasPersistedCredentials = (
|
|
22
|
+
state: MCPPersistedAuthState | null,
|
|
23
|
+
): boolean => Boolean(state?.tokens) || Boolean(state?.token);
|