@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
|
@@ -14,7 +14,7 @@ export namespace McpAddFormPrimitiveAuthFields {
|
|
|
14
14
|
export const McpAddFormPrimitiveAuthFields: FC<
|
|
15
15
|
McpAddFormPrimitiveAuthFields.Props
|
|
16
16
|
> = ({ children }) => {
|
|
17
|
-
const { state, setField } = useAddForm();
|
|
17
|
+
const { state, ids, setField } = useAddForm();
|
|
18
18
|
|
|
19
19
|
if (children) {
|
|
20
20
|
const Render = children;
|
|
@@ -23,25 +23,43 @@ export const McpAddFormPrimitiveAuthFields: FC<
|
|
|
23
23
|
|
|
24
24
|
if (state.authType === "bearer") {
|
|
25
25
|
return (
|
|
26
|
-
<
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
26
|
+
<div>
|
|
27
|
+
<label
|
|
28
|
+
htmlFor={ids.bearerToken}
|
|
29
|
+
data-mcp-auth-field-label="bearer-token"
|
|
30
|
+
>
|
|
31
|
+
Bearer token
|
|
32
|
+
</label>
|
|
33
|
+
<input
|
|
34
|
+
id={ids.bearerToken}
|
|
35
|
+
type="password"
|
|
36
|
+
value={state.bearerToken}
|
|
37
|
+
onChange={(e) => setField("bearerToken", e.target.value)}
|
|
38
|
+
aria-invalid={state.errorField === "bearerToken" ? true : undefined}
|
|
39
|
+
aria-describedby={
|
|
40
|
+
state.errorField === "bearerToken" ? ids.error : undefined
|
|
41
|
+
}
|
|
42
|
+
data-mcp-auth-field="bearer-token"
|
|
43
|
+
/>
|
|
44
|
+
</div>
|
|
33
45
|
);
|
|
34
46
|
}
|
|
35
47
|
|
|
36
48
|
if (state.authType === "oauth") {
|
|
37
49
|
return (
|
|
38
|
-
<
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
50
|
+
<div>
|
|
51
|
+
<label htmlFor={ids.scopes} data-mcp-auth-field-label="oauth-scopes">
|
|
52
|
+
OAuth scopes
|
|
53
|
+
</label>
|
|
54
|
+
<input
|
|
55
|
+
id={ids.scopes}
|
|
56
|
+
type="text"
|
|
57
|
+
placeholder="Scopes (space-separated, optional)"
|
|
58
|
+
value={state.scopes}
|
|
59
|
+
onChange={(e) => setField("scopes", e.target.value)}
|
|
60
|
+
data-mcp-auth-field="oauth-scopes"
|
|
61
|
+
/>
|
|
62
|
+
</div>
|
|
45
63
|
);
|
|
46
64
|
}
|
|
47
65
|
|
|
@@ -2,6 +2,7 @@ import {
|
|
|
2
2
|
type ComponentPropsWithoutRef,
|
|
3
3
|
type ComponentRef,
|
|
4
4
|
forwardRef,
|
|
5
|
+
isValidElement,
|
|
5
6
|
} from "react";
|
|
6
7
|
import { Primitive } from "@radix-ui/react-primitive";
|
|
7
8
|
import { useAddForm } from "./context";
|
|
@@ -15,13 +16,26 @@ export const McpAddFormPrimitiveError = forwardRef<
|
|
|
15
16
|
McpAddFormPrimitiveError.Element,
|
|
16
17
|
McpAddFormPrimitiveError.Props
|
|
17
18
|
>((props, ref) => {
|
|
18
|
-
const { state } = useAddForm();
|
|
19
|
+
const { state, ids } = useAddForm();
|
|
19
20
|
if (!state.error) return null;
|
|
20
|
-
|
|
21
|
-
|
|
21
|
+
const childId =
|
|
22
|
+
props.asChild && isValidElement<{ id?: string }>(props.children)
|
|
23
|
+
? props.children.props.id
|
|
24
|
+
: undefined;
|
|
25
|
+
const customId = childId ?? props.id;
|
|
26
|
+
const needsDescriptionWrapper =
|
|
27
|
+
customId !== undefined && customId !== ids.error;
|
|
28
|
+
const error = (
|
|
29
|
+
<Primitive.div
|
|
30
|
+
{...props}
|
|
31
|
+
id={needsDescriptionWrapper ? props.id : ids.error}
|
|
32
|
+
role={props.role ?? "alert"}
|
|
33
|
+
ref={ref}
|
|
34
|
+
>
|
|
22
35
|
{props.children ?? state.error}
|
|
23
36
|
</Primitive.div>
|
|
24
37
|
);
|
|
38
|
+
return needsDescriptionWrapper ? <div id={ids.error}>{error}</div> : error;
|
|
25
39
|
});
|
|
26
40
|
|
|
27
41
|
McpAddFormPrimitiveError.displayName = "McpAddFormPrimitive.Error";
|
|
@@ -18,12 +18,24 @@ export const McpAddFormPrimitiveNameField = forwardRef<
|
|
|
18
18
|
McpAddFormPrimitiveNameField.Element,
|
|
19
19
|
McpAddFormPrimitiveNameField.Props
|
|
20
20
|
>((props, ref) => {
|
|
21
|
-
const { state, setField } = useAddForm();
|
|
21
|
+
const { state, ids, setField } = useAddForm();
|
|
22
22
|
return (
|
|
23
23
|
<Primitive.input
|
|
24
24
|
type="text"
|
|
25
25
|
placeholder="Name"
|
|
26
26
|
{...props}
|
|
27
|
+
aria-invalid={
|
|
28
|
+
props["aria-invalid"] ??
|
|
29
|
+
(state.errorField === "name" ? true : undefined)
|
|
30
|
+
}
|
|
31
|
+
aria-describedby={
|
|
32
|
+
[
|
|
33
|
+
props["aria-describedby"],
|
|
34
|
+
state.errorField === "name" ? ids.error : null,
|
|
35
|
+
]
|
|
36
|
+
.filter(Boolean)
|
|
37
|
+
.join(" ") || undefined
|
|
38
|
+
}
|
|
27
39
|
ref={ref}
|
|
28
40
|
value={state.name}
|
|
29
41
|
onChange={(e) => setField("name", e.target.value)}
|
|
@@ -4,12 +4,17 @@ import {
|
|
|
4
4
|
type FormEventHandler,
|
|
5
5
|
forwardRef,
|
|
6
6
|
useCallback,
|
|
7
|
+
useId,
|
|
7
8
|
useMemo,
|
|
8
9
|
useState,
|
|
9
10
|
} from "react";
|
|
10
11
|
import { Primitive } from "@radix-ui/react-primitive";
|
|
11
12
|
import { useAui } from "@assistant-ui/store";
|
|
12
|
-
import {
|
|
13
|
+
import {
|
|
14
|
+
AddFormContext,
|
|
15
|
+
type AddFormFieldIds,
|
|
16
|
+
type AddFormState,
|
|
17
|
+
} from "./context";
|
|
13
18
|
import type { MCPAuthConfig } from "../../mcp-scope";
|
|
14
19
|
import { invokeMcpCallback } from "../../utils/invokeMcpCallback";
|
|
15
20
|
|
|
@@ -21,6 +26,7 @@ const INITIAL: AddFormState = {
|
|
|
21
26
|
scopes: "",
|
|
22
27
|
submitting: false,
|
|
23
28
|
error: null,
|
|
29
|
+
errorField: null,
|
|
24
30
|
};
|
|
25
31
|
|
|
26
32
|
function validateUrl(raw: string): { url: string } | { error: string } {
|
|
@@ -54,11 +60,30 @@ export const McpAddFormPrimitiveRoot = forwardRef<
|
|
|
54
60
|
McpAddFormPrimitiveRoot.Props
|
|
55
61
|
>(({ onSubmitted, onCancel, ...props }, ref) => {
|
|
56
62
|
const aui = useAui();
|
|
63
|
+
const formId = useId();
|
|
57
64
|
const [state, setState] = useState<AddFormState>(INITIAL);
|
|
65
|
+
const ids = useMemo<AddFormFieldIds>(
|
|
66
|
+
() => ({
|
|
67
|
+
bearerToken: `${formId}-bearer-token`,
|
|
68
|
+
scopes: `${formId}-oauth-scopes`,
|
|
69
|
+
error: `${formId}-error`,
|
|
70
|
+
}),
|
|
71
|
+
[formId],
|
|
72
|
+
);
|
|
58
73
|
|
|
59
74
|
const setField = useCallback(
|
|
60
75
|
<K extends keyof AddFormState>(key: K, value: AddFormState[K]) => {
|
|
61
|
-
setState((prev) =>
|
|
76
|
+
setState((prev) => {
|
|
77
|
+
const clearsError =
|
|
78
|
+
prev.errorField === "form" ||
|
|
79
|
+
prev.errorField === key ||
|
|
80
|
+
(key === "authType" && prev.errorField === "bearerToken");
|
|
81
|
+
return {
|
|
82
|
+
...prev,
|
|
83
|
+
[key]: value,
|
|
84
|
+
...(clearsError ? { error: null, errorField: null } : {}),
|
|
85
|
+
};
|
|
86
|
+
});
|
|
62
87
|
},
|
|
63
88
|
[],
|
|
64
89
|
);
|
|
@@ -87,19 +112,36 @@ export const McpAddFormPrimitiveRoot = forwardRef<
|
|
|
87
112
|
const submit = useCallback(async () => {
|
|
88
113
|
if (state.submitting) return;
|
|
89
114
|
if (!state.name.trim()) {
|
|
90
|
-
setState((p) => ({
|
|
115
|
+
setState((p) => ({
|
|
116
|
+
...p,
|
|
117
|
+
error: "Name is required",
|
|
118
|
+
errorField: "name",
|
|
119
|
+
}));
|
|
91
120
|
return;
|
|
92
121
|
}
|
|
93
122
|
if (state.authType === "bearer" && !state.bearerToken.trim()) {
|
|
94
|
-
setState((p) => ({
|
|
123
|
+
setState((p) => ({
|
|
124
|
+
...p,
|
|
125
|
+
error: "Bearer token is required",
|
|
126
|
+
errorField: "bearerToken",
|
|
127
|
+
}));
|
|
95
128
|
return;
|
|
96
129
|
}
|
|
97
130
|
const urlResult = validateUrl(state.url);
|
|
98
131
|
if ("error" in urlResult) {
|
|
99
|
-
setState((p) => ({
|
|
132
|
+
setState((p) => ({
|
|
133
|
+
...p,
|
|
134
|
+
error: urlResult.error,
|
|
135
|
+
errorField: "url",
|
|
136
|
+
}));
|
|
100
137
|
return;
|
|
101
138
|
}
|
|
102
|
-
setState((p) => ({
|
|
139
|
+
setState((p) => ({
|
|
140
|
+
...p,
|
|
141
|
+
submitting: true,
|
|
142
|
+
error: null,
|
|
143
|
+
errorField: null,
|
|
144
|
+
}));
|
|
103
145
|
try {
|
|
104
146
|
const id = await aui.mcp.addCustomServer({
|
|
105
147
|
name: state.name.trim(),
|
|
@@ -113,6 +155,7 @@ export const McpAddFormPrimitiveRoot = forwardRef<
|
|
|
113
155
|
...p,
|
|
114
156
|
submitting: false,
|
|
115
157
|
error: err instanceof Error ? err.message : String(err),
|
|
158
|
+
errorField: "form",
|
|
116
159
|
}));
|
|
117
160
|
}
|
|
118
161
|
}, [aui, buildAuth, onSubmitted, state]);
|
|
@@ -123,8 +166,8 @@ export const McpAddFormPrimitiveRoot = forwardRef<
|
|
|
123
166
|
}, [onCancel]);
|
|
124
167
|
|
|
125
168
|
const value = useMemo(
|
|
126
|
-
() => ({ state, setField, reset, submit, cancel }),
|
|
127
|
-
[state, setField, reset, submit, cancel],
|
|
169
|
+
() => ({ state, ids, setField, reset, submit, cancel }),
|
|
170
|
+
[state, ids, setField, reset, submit, cancel],
|
|
128
171
|
);
|
|
129
172
|
|
|
130
173
|
const onFormSubmit: FormEventHandler<HTMLFormElement> = (e) => {
|
|
@@ -18,13 +18,24 @@ export const McpAddFormPrimitiveUrlField = forwardRef<
|
|
|
18
18
|
McpAddFormPrimitiveUrlField.Element,
|
|
19
19
|
McpAddFormPrimitiveUrlField.Props
|
|
20
20
|
>((props, ref) => {
|
|
21
|
-
const { state, setField } = useAddForm();
|
|
21
|
+
const { state, ids, setField } = useAddForm();
|
|
22
22
|
return (
|
|
23
23
|
<Primitive.input
|
|
24
24
|
type="url"
|
|
25
25
|
inputMode="url"
|
|
26
26
|
placeholder="https://example.com/mcp"
|
|
27
27
|
{...props}
|
|
28
|
+
aria-invalid={
|
|
29
|
+
props["aria-invalid"] ?? (state.errorField === "url" ? true : undefined)
|
|
30
|
+
}
|
|
31
|
+
aria-describedby={
|
|
32
|
+
[
|
|
33
|
+
props["aria-describedby"],
|
|
34
|
+
state.errorField === "url" ? ids.error : null,
|
|
35
|
+
]
|
|
36
|
+
.filter(Boolean)
|
|
37
|
+
.join(" ") || undefined
|
|
38
|
+
}
|
|
28
39
|
ref={ref}
|
|
29
40
|
value={state.url}
|
|
30
41
|
onChange={(e) => setField("url", e.target.value)}
|
|
@@ -3,6 +3,14 @@ import type { MCPAuthConfig } from "../../mcp-scope";
|
|
|
3
3
|
|
|
4
4
|
export type AddFormAuthType = MCPAuthConfig["type"];
|
|
5
5
|
|
|
6
|
+
export type AddFormErrorField = "name" | "url" | "bearerToken" | "form" | null;
|
|
7
|
+
|
|
8
|
+
export type AddFormFieldIds = {
|
|
9
|
+
bearerToken: string;
|
|
10
|
+
scopes: string;
|
|
11
|
+
error: string;
|
|
12
|
+
};
|
|
13
|
+
|
|
6
14
|
export type AddFormState = {
|
|
7
15
|
name: string;
|
|
8
16
|
url: string;
|
|
@@ -11,10 +19,12 @@ export type AddFormState = {
|
|
|
11
19
|
scopes: string;
|
|
12
20
|
submitting: boolean;
|
|
13
21
|
error: string | null;
|
|
22
|
+
errorField: AddFormErrorField;
|
|
14
23
|
};
|
|
15
24
|
|
|
16
25
|
export type AddFormContextValue = {
|
|
17
26
|
state: AddFormState;
|
|
27
|
+
ids: AddFormFieldIds;
|
|
18
28
|
setField: <K extends keyof AddFormState>(
|
|
19
29
|
key: K,
|
|
20
30
|
value: AddFormState[K],
|