@assistant-ui/mcp-docs-server 0.2.0 → 0.2.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.
- package/.docs/organized/code-examples/waterfall.md +12 -13
- package/.docs/organized/code-examples/with-a2a.md +16 -11
- package/.docs/organized/code-examples/with-ag-ui.md +15 -13
- package/.docs/organized/code-examples/with-ai-sdk-v7.md +14 -13
- package/.docs/organized/code-examples/with-artifacts.md +14 -13
- package/.docs/organized/code-examples/with-assistant-transport.md +20 -28
- package/.docs/organized/code-examples/with-browser-extension.md +18 -11
- package/.docs/organized/code-examples/with-chain-of-thought.md +17 -15
- package/.docs/organized/code-examples/with-cloud-standalone.md +10 -11
- package/.docs/organized/code-examples/with-cloud.md +19 -14
- package/.docs/organized/code-examples/with-custom-thread-list.md +15 -14
- package/.docs/organized/code-examples/with-elevenlabs-conversational.md +14 -14
- package/.docs/organized/code-examples/with-elevenlabs-scribe.md +19 -17
- package/.docs/organized/code-examples/with-eve.md +66 -12
- package/.docs/organized/code-examples/with-expo.md +26 -31
- package/.docs/organized/code-examples/with-external-store.md +17 -12
- package/.docs/organized/code-examples/with-ffmpeg.md +21 -15
- package/.docs/organized/code-examples/with-generative-ui.md +271 -36
- package/.docs/organized/code-examples/with-google-adk.md +17 -12
- package/.docs/organized/code-examples/with-heat-graph.md +6 -7
- package/.docs/organized/code-examples/with-image-generation.md +9 -10
- package/.docs/organized/code-examples/with-interactables.md +14 -13
- package/.docs/organized/code-examples/with-langchain.md +12 -13
- package/.docs/organized/code-examples/with-langgraph.md +19 -13
- package/.docs/organized/code-examples/with-livekit.md +13 -13
- package/.docs/organized/code-examples/with-mcp.md +14 -15
- package/.docs/organized/code-examples/with-nuxt.md +2428 -0
- package/.docs/organized/code-examples/with-opencode.md +23 -14
- package/.docs/organized/code-examples/with-openui.md +449 -0
- package/.docs/organized/code-examples/with-pi.md +59 -57
- package/.docs/organized/code-examples/with-react-hook-form.md +16 -15
- package/.docs/organized/code-examples/with-react-ink-web.md +7 -8
- package/.docs/organized/code-examples/with-react-ink.md +6 -6
- package/.docs/organized/code-examples/with-react-router.md +17 -11
- package/.docs/organized/code-examples/with-resumable-stream.md +12 -13
- package/.docs/organized/code-examples/with-store.md +27 -16
- package/.docs/organized/code-examples/with-svelte.md +415 -0
- package/.docs/organized/code-examples/with-sveltekit.md +1061 -0
- package/.docs/organized/code-examples/with-tanstack.md +19 -13
- package/.docs/organized/code-examples/with-tap-runtime.md +15 -15
- package/.docs/organized/code-examples/with-virtualized-thread.md +8 -9
- package/.docs/organized/code-examples/with-vue.md +408 -0
- package/.docs/raw/docs/(docs)/cli.mdx +7 -2
- package/.docs/raw/docs/(docs)/index.mdx +9 -76
- package/.docs/raw/docs/(docs)/installation.mdx +6 -20
- package/.docs/raw/docs/(reference)/api-reference/context-providers/assistant-runtime-provider.mdx +24 -4
- package/.docs/raw/docs/(reference)/api-reference/generative-ui/slack.mdx +5 -1
- package/.docs/raw/docs/(reference)/api-reference/generative-ui/teams.mdx +9 -2
- package/.docs/raw/docs/(reference)/api-reference/hooks/primitives.mdx +2 -2
- package/.docs/raw/docs/(reference)/api-reference/integrations/eve.mdx +47 -1
- package/.docs/raw/docs/(reference)/api-reference/integrations/react-ai-sdk.mdx +29 -4
- package/.docs/raw/docs/(reference)/api-reference/tools/status.mdx +1 -1
- package/.docs/raw/docs/(reference)/api-reference/utilities/miscellaneous.mdx +52 -1
- package/.docs/raw/docs/(reference)/api-reference/voice/session.mdx +1 -1
- package/.docs/raw/docs/cloud/ai-sdk-assistant-ui.mdx +2 -2
- package/.docs/raw/docs/cloud/ai-sdk.mdx +4 -4
- package/.docs/raw/docs/cloud/index.mdx +1 -1
- package/.docs/raw/docs/copilots/model-context.mdx +4 -3
- package/.docs/raw/docs/copilots/motivation.mdx +4 -4
- package/.docs/raw/docs/guides/attachments.mdx +2 -2
- package/.docs/raw/docs/guides/chain-of-thought.mdx +1 -1
- package/.docs/raw/docs/guides/context-api.mdx +15 -17
- package/.docs/raw/docs/guides/dictation.mdx +1 -1
- package/.docs/raw/docs/guides/electron.mdx +1 -1
- package/.docs/raw/docs/guides/mentions.mdx +2 -0
- package/.docs/raw/docs/guides/resumable-streams.mdx +74 -3
- package/.docs/raw/docs/guides/suggestions.mdx +15 -12
- package/.docs/raw/docs/ink/hooks.mdx +9 -4
- package/.docs/raw/docs/ink/primitives.mdx +5 -4
- package/.docs/raw/docs/integrations/attachments/custom-adapter.mdx +16 -0
- package/.docs/raw/docs/integrations/auth/better-auth.mdx +1 -1
- package/.docs/raw/docs/integrations/auth/clerk.mdx +1 -1
- package/.docs/raw/docs/integrations/auth/next-auth.mdx +1 -1
- package/.docs/raw/docs/integrations/frameworks/cloudflare-agents/overview.mdx +1 -1
- package/.docs/raw/docs/integrations/frameworks/mastra/full-stack.mdx +2 -2
- package/.docs/raw/docs/integrations/frameworks/mastra/separate-server.mdx +1 -1
- package/.docs/raw/docs/integrations/gateways/index.mdx +2 -2
- package/.docs/raw/docs/integrations/observability/helicone.mdx +2 -2
- package/.docs/raw/docs/integrations/observability/langfuse.mdx +1 -1
- package/.docs/raw/docs/integrations/observability/langsmith.mdx +2 -2
- package/.docs/raw/docs/integrations/persistence/custom-adapter.mdx +146 -128
- package/.docs/raw/docs/migrations/toolkit-tools.mdx +15 -13
- package/.docs/raw/docs/migrations/v0-15.mdx +118 -4
- package/.docs/raw/docs/primitives/attachment.mdx +2 -2
- package/.docs/raw/docs/primitives/composer.mdx +2 -2
- package/.docs/raw/docs/primitives/message.mdx +33 -1
- package/.docs/raw/docs/primitives/suggestion.mdx +4 -2
- package/.docs/raw/docs/primitives/thread.mdx +1 -1
- package/.docs/raw/docs/react-native/hooks.mdx +14 -4
- package/.docs/raw/docs/react-native/index.mdx +1 -1
- package/.docs/raw/docs/react-native/primitives.mdx +2 -2
- package/.docs/raw/docs/runtimes/ag-ui/runtime-options.mdx +35 -5
- package/.docs/raw/docs/runtimes/ai-sdk/v4-legacy.mdx +1 -1
- package/.docs/raw/docs/runtimes/ai-sdk/v5-legacy.mdx +1 -1
- package/.docs/raw/docs/runtimes/ai-sdk/v6-legacy.mdx +9 -10
- package/.docs/raw/docs/runtimes/ai-sdk/v7.mdx +9 -10
- package/.docs/raw/docs/runtimes/claude-managed-agents.mdx +118 -0
- package/.docs/raw/docs/runtimes/concepts/stability.mdx +2 -1
- package/.docs/raw/docs/runtimes/concepts/threads.mdx +106 -27
- package/.docs/raw/docs/runtimes/custom/assistant-transport.mdx +19 -1
- package/.docs/raw/docs/runtimes/custom/external-store.mdx +34 -1
- package/.docs/raw/docs/runtimes/custom/local-runtime.mdx +36 -9
- package/.docs/raw/docs/runtimes/eve/overview.mdx +51 -0
- package/.docs/raw/docs/runtimes/eve/quickstart.mdx +51 -2
- package/.docs/raw/docs/runtimes/google-adk/hooks.mdx +9 -12
- package/.docs/raw/docs/runtimes/langchain.mdx +1 -1
- package/.docs/raw/docs/runtimes/langgraph/streaming.mdx +5 -1
- package/.docs/raw/docs/runtimes/langgraph/tutorial/part-2.mdx +7 -7
- package/.docs/raw/docs/runtimes/langgraph/tutorial/part-3.mdx +4 -4
- package/.docs/raw/docs/runtimes/opencode/hooks.mdx +1 -0
- package/.docs/raw/docs/runtimes/opencode/overview.mdx +10 -0
- package/.docs/raw/docs/runtimes/pick-a-runtime.mdx +8 -1
- package/.docs/raw/docs/tools/backend.mdx +2 -2
- package/.docs/raw/docs/tools/defining-tools.mdx +28 -7
- package/.docs/raw/docs/tools/dynamic-tools.mdx +6 -4
- package/.docs/raw/docs/tools/generative-ui-primitive.mdx +180 -0
- package/.docs/raw/docs/tools/generative-ui-slack.mdx +167 -0
- package/.docs/raw/docs/tools/generative-ui-teams.mdx +160 -0
- package/.docs/raw/docs/tools/generative-ui.mdx +224 -211
- package/.docs/raw/docs/tools/index.mdx +2 -1
- package/.docs/raw/docs/tools/interactables.mdx +29 -17
- package/.docs/raw/docs/tools/mcp-apps.mdx +35 -6
- package/.docs/raw/docs/tools/mcp.mdx +9 -7
- package/.docs/raw/docs/tools/openui.mdx +175 -0
- package/.docs/raw/docs/tools/tool-ui.mdx +27 -24
- package/.docs/raw/docs/tools/user-managed-mcp.mdx +17 -8
- package/.docs/raw/docs/ui/attachment.mdx +27 -0
- package/.docs/raw/docs/ui/file.mdx +7 -2
- package/.docs/raw/docs/ui/image.mdx +1 -1
- package/.docs/raw/docs/ui/mcp-config.mdx +8 -3
- package/.docs/raw/docs/ui/model-selector.mdx +8 -8
- package/.docs/raw/docs/ui/part-grouping.mdx +1 -1
- package/.docs/raw/docs/ui/thread.mdx +24 -5
- package/.docs/raw/docs/utilities/react-o11y.mdx +7 -9
- package/dist/constants.js +2 -2
- package/dist/constants.js.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/prepare-docs/prepare.js.map +1 -1
- package/dist/tools/docs.js +4 -2
- package/dist/tools/docs.js.map +1 -1
- package/dist/tools/examples.js +2 -1
- package/dist/tools/examples.js.map +1 -1
- package/dist/tools/resources.js +2 -1
- package/dist/tools/resources.js.map +1 -1
- package/dist/tools/tests/test-setup.js +2 -1
- package/dist/tools/tests/test-setup.js.map +1 -1
- package/dist/tools/xulux-templates.js +4 -2
- package/dist/tools/xulux-templates.js.map +1 -1
- package/dist/utils/mdx.js +2 -1
- package/dist/utils/mdx.js.map +1 -1
- package/dist/xulux/catalog-client.js +1 -1
- package/dist/xulux/catalog-client.js.map +1 -1
- package/package.json +4 -4
- package/src/tools/tests/docs.test.ts +2 -2
- package/.docs/raw/docs/tools/interactables-legacy.mdx +0 -410
|
@@ -41,7 +41,7 @@ Interactables allow both agents and users to read and edit tool UIs and componen
|
|
|
41
41
|
|
|
42
42
|
```tsx
|
|
43
43
|
import {
|
|
44
|
-
|
|
44
|
+
AuiConfig,
|
|
45
45
|
unstable_Interactables,
|
|
46
46
|
AssistantRuntimeProvider,
|
|
47
47
|
Tools,
|
|
@@ -50,13 +50,15 @@ import { useChatRuntime } from "@assistant-ui/react-ai-sdk";
|
|
|
50
50
|
|
|
51
51
|
function MyRuntimeProvider({ children }: { children: React.ReactNode }) {
|
|
52
52
|
const runtime = useChatRuntime();
|
|
53
|
-
|
|
54
|
-
const aui = useAui({
|
|
53
|
+
const config = AuiConfig({
|
|
55
54
|
unstable_interactables: unstable_Interactables(), // [!code ++]
|
|
56
55
|
});
|
|
57
56
|
|
|
58
57
|
return (
|
|
59
|
-
<AssistantRuntimeProvider
|
|
58
|
+
<AssistantRuntimeProvider
|
|
59
|
+
runtime={runtime}
|
|
60
|
+
config={config}
|
|
61
|
+
>
|
|
60
62
|
{children}
|
|
61
63
|
</AssistantRuntimeProvider>
|
|
62
64
|
);
|
|
@@ -64,9 +66,10 @@ function MyRuntimeProvider({ children }: { children: React.ReactNode }) {
|
|
|
64
66
|
```
|
|
65
67
|
|
|
66
68
|
<Callout type="idea">
|
|
67
|
-
The
|
|
68
|
-
`
|
|
69
|
-
|
|
69
|
+
The deprecated [`interactables:
|
|
70
|
+
Interactables()`](/docs/api-reference/tools/interactables-legacy) scope and the
|
|
71
|
+
new `unstable_interactables: unstable_Interactables()` scope are mutually
|
|
72
|
+
exclusive. Mount only one interactables API in a single provider config.
|
|
70
73
|
</Callout>
|
|
71
74
|
|
|
72
75
|
This scope is needed for both kinds of interactable. Thread-scoped interactables also live in a toolkit, which you register with `Tools` (shown below).
|
|
@@ -166,7 +169,7 @@ const toolkit = defineToolkit({
|
|
|
166
169
|
Register the toolkit alongside the `unstable_Interactables` scope:
|
|
167
170
|
|
|
168
171
|
```tsx
|
|
169
|
-
|
|
172
|
+
AuiConfig({
|
|
170
173
|
unstable_interactables: unstable_Interactables(),
|
|
171
174
|
tools: Tools({ toolkit }), // [!code ++]
|
|
172
175
|
});
|
|
@@ -199,7 +202,7 @@ export async function POST(req: Request) {
|
|
|
199
202
|
const { messages } = await req.json();
|
|
200
203
|
|
|
201
204
|
const result = streamText({
|
|
202
|
-
model: openai("gpt-5.
|
|
205
|
+
model: openai("gpt-5.6-luna"),
|
|
203
206
|
messages: await convertToModelMessages(injectInteractableContext(messages)), // [!code ++]
|
|
204
207
|
});
|
|
205
208
|
|
|
@@ -592,7 +595,12 @@ An app-scoped item's history covers the current conversation, not its full cross
|
|
|
592
595
|
By default, app-scoped interactable state is in-memory and lost on page refresh. You can add persistence by passing an adapter to `unstable_Interactables`:
|
|
593
596
|
|
|
594
597
|
```tsx
|
|
595
|
-
import {
|
|
598
|
+
import {
|
|
599
|
+
AuiConfig,
|
|
600
|
+
AuiProvider,
|
|
601
|
+
useAui,
|
|
602
|
+
unstable_Interactables,
|
|
603
|
+
} from "@assistant-ui/react";
|
|
596
604
|
|
|
597
605
|
// Module-level (or memoized) so the adapter identity is stable across renders.
|
|
598
606
|
const persistenceAdapter = {
|
|
@@ -606,19 +614,23 @@ const persistenceAdapter = {
|
|
|
606
614
|
};
|
|
607
615
|
|
|
608
616
|
function MyRuntimeProvider({ children }) {
|
|
609
|
-
const aui = useAui(
|
|
617
|
+
const aui = useAui();
|
|
618
|
+
const config = AuiConfig({
|
|
610
619
|
unstable_interactables: unstable_Interactables({
|
|
611
620
|
persistence: persistenceAdapter,
|
|
612
621
|
}),
|
|
613
622
|
});
|
|
614
|
-
|
|
615
|
-
|
|
623
|
+
return (
|
|
624
|
+
<AuiProvider extends={aui} config={config}>
|
|
625
|
+
{children}
|
|
626
|
+
</AuiProvider>
|
|
627
|
+
);
|
|
616
628
|
}
|
|
617
629
|
```
|
|
618
630
|
|
|
619
631
|
`load` is called when the adapter is attached and may be async. Loaded state seeds interactables as they register; a local edit made while a slow `load` is still in flight wins over the loaded value. Thread-scoped interactables are not touched by the adapter; they persist via thread history.
|
|
620
632
|
|
|
621
|
-
For dynamic setups (an adapter that depends on auth), call `aui.
|
|
633
|
+
For dynamic setups (an adapter that depends on auth), call `aui.unstable_interactables.setPersistenceAdapter(adapter)` imperatively instead. Replacing or removing an adapter flushes queued changes through the outgoing adapter before the new persistence context is attached.
|
|
622
634
|
|
|
623
635
|
### Sync Status
|
|
624
636
|
|
|
@@ -700,7 +712,7 @@ Inside a thread-scoped `render`, `streaming: true` carries the same live state:
|
|
|
700
712
|
|
|
701
713
|
## Multiple Instances
|
|
702
714
|
|
|
703
|
-
A `name` can have many live instances at once. They all share one `update_{name}` tool: the model addresses an instance with the tool's `id` parameter, which it reads from the state snapshots in the conversation. The tool's name, schema, and description never change as instances mount and unmount, so the model's tool list (and provider prompt caches) stay stable.
|
|
715
|
+
A `name` can have many live instances at once. They all share one `update_{name}` tool: the model addresses an instance with the tool's `id` parameter, which it reads from the state snapshots in the conversation. The tool's name, schema, and description never change as instances mount and unmount, so the model's tool list (and provider prompt caches) stay stable. The schema marks `id` as required, so the model is expected to send it on every call; the runtime still resolves an id-less call while exactly one instance exists. A call with an unknown `id` returns an error listing the valid ids, so the model can recover.
|
|
704
716
|
|
|
705
717
|
How instances come into being differs by scope.
|
|
706
718
|
|
|
@@ -1040,10 +1052,10 @@ Every version of an interactable recorded in the current thread, oldest first. E
|
|
|
1040
1052
|
|
|
1041
1053
|
### `unstable_Interactables`
|
|
1042
1054
|
|
|
1043
|
-
The scope resource that manages all interactables. Register it via `
|
|
1055
|
+
The scope resource that manages all interactables. Register it via your provider's `config`, optionally with a [persistence adapter](#persistence):
|
|
1044
1056
|
|
|
1045
1057
|
```tsx
|
|
1046
|
-
|
|
1058
|
+
AuiConfig({
|
|
1047
1059
|
unstable_interactables: unstable_Interactables({ persistence: myAdapter }),
|
|
1048
1060
|
});
|
|
1049
1061
|
```
|
|
@@ -36,14 +36,17 @@ Compose `McpAppRenderer({...})` into your `Tools` resource. Provide `host.url` p
|
|
|
36
36
|
|
|
37
37
|
```tsx
|
|
38
38
|
import {
|
|
39
|
-
|
|
39
|
+
AuiConfig,
|
|
40
|
+
AuiProvider,
|
|
40
41
|
Tools,
|
|
41
42
|
McpAppRenderer,
|
|
42
43
|
McpAppsRemoteHost,
|
|
44
|
+
useAui,
|
|
43
45
|
} from "@assistant-ui/react";
|
|
44
46
|
|
|
45
|
-
function MyAssistant() {
|
|
46
|
-
useAui(
|
|
47
|
+
function MyAssistant({ children }) {
|
|
48
|
+
const aui = useAui();
|
|
49
|
+
const config = AuiConfig({
|
|
47
50
|
tools: Tools({
|
|
48
51
|
toolkit: myToolkit,
|
|
49
52
|
mcpApp: McpAppRenderer({
|
|
@@ -53,12 +56,38 @@ function MyAssistant() {
|
|
|
53
56
|
}),
|
|
54
57
|
}),
|
|
55
58
|
});
|
|
56
|
-
|
|
59
|
+
return (
|
|
60
|
+
<AuiProvider extends={aui} config={config}>
|
|
61
|
+
{children}
|
|
62
|
+
</AuiProvider>
|
|
63
|
+
);
|
|
57
64
|
}
|
|
58
65
|
```
|
|
59
66
|
|
|
60
67
|
`McpAppsRemoteHost` is the default host strategy — it POSTs `{ method, params }` to your route. A different strategy (e.g. a client-side MCP client) can be plugged in by writing a custom resource that returns the same `McpAppsHost` shape (`{ loadResource, callTool, readResource, listResources }`).
|
|
61
68
|
|
|
69
|
+
Changes to `headers` or a custom `fetch` function apply to subsequent host requests without reloading the widget. When the account or workspace identity changes, key the host resource explicitly so its UI resource reloads.
|
|
70
|
+
|
|
71
|
+
Install the resource helper:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
pnpm add @assistant-ui/tap
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
```tsx
|
|
78
|
+
import { withKey } from "@assistant-ui/tap";
|
|
79
|
+
|
|
80
|
+
const mcpApp = McpAppRenderer({
|
|
81
|
+
host: withKey(
|
|
82
|
+
workspaceId,
|
|
83
|
+
McpAppsRemoteHost({
|
|
84
|
+
url: "/api/mcp-apps",
|
|
85
|
+
headers: () => getWorkspaceHeaders(workspaceId),
|
|
86
|
+
}),
|
|
87
|
+
),
|
|
88
|
+
});
|
|
89
|
+
```
|
|
90
|
+
|
|
62
91
|
`openLink` is auto-wired to `window.open(url, "_blank", "noopener,noreferrer")`. `sendMessage` is auto-wired to append a user message to the current thread (accepts `string`, `{ prompt }`, `{ text }`, or `{ message }`).
|
|
63
92
|
|
|
64
93
|
### Route handler
|
|
@@ -154,7 +183,7 @@ const tools = await client.listTools();
|
|
|
154
183
|
const { modelVisible } = splitMcpAppTools(tools);
|
|
155
184
|
|
|
156
185
|
const result = streamText({
|
|
157
|
-
model: openai("gpt-5.
|
|
186
|
+
model: openai("gpt-5.6-luna"),
|
|
158
187
|
tools: modelVisible.tools,
|
|
159
188
|
// ...
|
|
160
189
|
});
|
|
@@ -314,4 +343,4 @@ McpAppRenderer({
|
|
|
314
343
|
- Widgets run cross-origin in a sandboxed iframe. The bridge filters incoming messages by both source window and origin.
|
|
315
344
|
- The host route is your auth boundary — apply session checks, rate limiting, and per-tool allowlists there. The renderer trusts whatever the route returns.
|
|
316
345
|
- `openLink` rejects non-`http(s)` URLs at the bridge layer, but your `openLink` handler should still treat the URL as untrusted (e.g. always use `noopener,noreferrer`).
|
|
317
|
-
- Keep `host` and `handlers` references stable across renders (e.g. module-scope constants or `useMemo`); an unstable identity
|
|
346
|
+
- Keep custom `host` and `handlers` references stable across renders (e.g. module-scope constants or `useMemo`); an unstable custom-host identity keeps the widget in `loadingFallback` while refetching on every parent re-render.
|
|
@@ -177,7 +177,7 @@ export async function POST(req: Request) {
|
|
|
177
177
|
const aiToolkit = new AISDKToolkit({ toolkit });
|
|
178
178
|
|
|
179
179
|
const result = streamText({
|
|
180
|
-
model: openai("gpt-5.
|
|
180
|
+
model: openai("gpt-5.6-luna"),
|
|
181
181
|
messages: await convertToModelMessages(messages),
|
|
182
182
|
tools: await aiToolkit.tools({ frontend: tools }),
|
|
183
183
|
onFinish: async () => {
|
|
@@ -220,7 +220,7 @@ export async function POST(req: Request) {
|
|
|
220
220
|
const tools = await mcpClient.tools();
|
|
221
221
|
|
|
222
222
|
const result = streamText({
|
|
223
|
-
model: openai("gpt-5.
|
|
223
|
+
model: openai("gpt-5.6-luna"),
|
|
224
224
|
messages: await convertToModelMessages(messages),
|
|
225
225
|
tools,
|
|
226
226
|
onFinish: async () => {
|
|
@@ -369,7 +369,7 @@ Register the toolkit once with `Tools({ toolkit })`. Renderer keys such as
|
|
|
369
369
|
```tsx title="app/components/RuntimeProvider.tsx"
|
|
370
370
|
"use client";
|
|
371
371
|
|
|
372
|
-
import { AssistantRuntimeProvider,
|
|
372
|
+
import { AssistantRuntimeProvider, AuiConfig, Tools } from "@assistant-ui/react";
|
|
373
373
|
import { useChatRuntime } from "@assistant-ui/react-ai-sdk";
|
|
374
374
|
import type { ReactNode } from "react";
|
|
375
375
|
|
|
@@ -377,10 +377,12 @@ import { toolkit } from "./GitHubIssueToolUI";
|
|
|
377
377
|
|
|
378
378
|
export function MyRuntimeProvider({ children }: { children: ReactNode }) {
|
|
379
379
|
const runtime = useChatRuntime();
|
|
380
|
-
const
|
|
381
|
-
|
|
380
|
+
const config = AuiConfig({ tools: Tools({ toolkit }) });
|
|
382
381
|
return (
|
|
383
|
-
<AssistantRuntimeProvider
|
|
382
|
+
<AssistantRuntimeProvider
|
|
383
|
+
runtime={runtime}
|
|
384
|
+
config={config}
|
|
385
|
+
>
|
|
384
386
|
{children}
|
|
385
387
|
</AssistantRuntimeProvider>
|
|
386
388
|
);
|
|
@@ -400,7 +402,7 @@ MCP tools execute on the server, so approval is a server-side tool gate, not a `
|
|
|
400
402
|
const tools = await mcpClient.tools();
|
|
401
403
|
|
|
402
404
|
const result = streamText({
|
|
403
|
-
model: openai("gpt-5.
|
|
405
|
+
model: openai("gpt-5.6-luna"),
|
|
404
406
|
messages: await convertToModelMessages(messages),
|
|
405
407
|
tools,
|
|
406
408
|
toolApproval: {
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: OpenUI
|
|
3
|
+
description: Render streaming OpenUI Lang interfaces in an assistant-ui conversation with @openuidev/assistant-ui, the integration package published by OpenUI.
|
|
4
|
+
platforms: ["react"]
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
[OpenUI](https://www.openui.com) is a generative UI system in which the model writes **OpenUI Lang**, a streaming markup language, and an OpenUI renderer turns it into interactive React components. [`@openuidev/assistant-ui`](https://www.npmjs.com/package/@openuidev/assistant-ui) connects that renderer to assistant-ui: it ships a ready-made toolkit, model instructions generated from the OpenUI component library, and Tool UI renderers that stream, handle interactions, and replay.
|
|
8
|
+
|
|
9
|
+
<Callout type="info">
|
|
10
|
+
`@openuidev/assistant-ui` is a third-party package. OpenUI owns the package, its [documentation](https://www.openui.com/docs/api-reference/assistant-ui), and its releases; assistant-ui does not ship or version any OpenUI code. Use OpenUI's reference for the package API and OpenUI Lang itself; this page covers the assistant-ui side of the wiring.
|
|
11
|
+
</Callout>
|
|
12
|
+
|
|
13
|
+
The integration rides entirely on the [Tool UI](/docs/tools/tool-ui) lifecycle, so assistant-ui stays in charge of the conversation, streaming, and tool calls. The toolkit registers two standalone tools:
|
|
14
|
+
|
|
15
|
+
- `present_openui` is a **frontend tool** for display-only interfaces (cards, tables, charts). It completes as soon as the streamed `ui` argument is available, and the turn ends there.
|
|
16
|
+
- `prompt_openui` is a **human tool** for forms and choices. It completes only when the user submits an OpenUI `@ToAssistant(...)` action, and the submitted values continue the conversation.
|
|
17
|
+
|
|
18
|
+
## How it relates to the `present` tool
|
|
19
|
+
|
|
20
|
+
assistant-ui's first-party [Generative UI](/docs/tools/generative-ui) follows the same shape: one tool, a component vocabulary, and a model that composes an interface at runtime. The difference is the representation and who owns it. `present` takes a JSON tree validated against a schema generated from a vocabulary you ship and restyle; `present_openui` takes an OpenUI Lang program rendered by OpenUI's component kit, taught to the model through instructions. Pick `present` when you want the interface built from your own components on assistant-ui's append-only surface, and OpenUI when you are already invested in the OpenUI ecosystem or want its renderer and component library.
|
|
21
|
+
|
|
22
|
+
## Quick start
|
|
23
|
+
|
|
24
|
+
The complete setup below runs in [`examples/with-openui`](https://github.com/assistant-ui/assistant-ui/tree/main/examples/with-openui). To scaffold a standalone copy, run `npx assistant-ui create my-app --example with-openui`.
|
|
25
|
+
|
|
26
|
+
<Steps>
|
|
27
|
+
|
|
28
|
+
<Step>
|
|
29
|
+
|
|
30
|
+
### Install the packages
|
|
31
|
+
|
|
32
|
+
Alongside an existing `@assistant-ui/react` setup, add the integration and its OpenUI peer dependencies:
|
|
33
|
+
|
|
34
|
+
<InstallCommand npm={["@openuidev/assistant-ui", "@openuidev/react-ui", "@openuidev/react-lang", "@openuidev/react-headless", "zustand@^4.5.5"]} />
|
|
35
|
+
|
|
36
|
+
The package also expects `zod` and React 18 or 19, which an assistant-ui app already has. The current OpenUI peers support AI SDK 6 and 7 and require Zustand 4.
|
|
37
|
+
|
|
38
|
+
</Step>
|
|
39
|
+
|
|
40
|
+
<Step>
|
|
41
|
+
|
|
42
|
+
### Load the OpenUI stylesheet
|
|
43
|
+
|
|
44
|
+
Import the layered stylesheet once, for example in `app/globals.css`:
|
|
45
|
+
|
|
46
|
+
```css
|
|
47
|
+
@import "@openuidev/react-ui/layered/styles/index.css";
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
</Step>
|
|
51
|
+
|
|
52
|
+
<Step>
|
|
53
|
+
|
|
54
|
+
### Register the toolkit and instructions
|
|
55
|
+
|
|
56
|
+
`openuiIntegration` bundles a toolkit and an instruction string created from the same OpenUI component library, so the model and the renderer share one vocabulary. Register the toolkit with [`Tools`](/docs/api-reference/tools) and mount `OpenUIInstructions` so the vocabulary reaches the model as assistant instructions:
|
|
57
|
+
|
|
58
|
+
```tsx title="app/page.tsx"
|
|
59
|
+
"use client";
|
|
60
|
+
|
|
61
|
+
import {
|
|
62
|
+
AssistantRuntimeProvider,
|
|
63
|
+
AuiConfig,
|
|
64
|
+
Tools,
|
|
65
|
+
} from "@assistant-ui/react";
|
|
66
|
+
import { useChatRuntime } from "@assistant-ui/react-ai-sdk";
|
|
67
|
+
import { OpenUIInstructions, openuiIntegration } from "@openuidev/assistant-ui";
|
|
68
|
+
import { shouldContinueAfterOpenUIPrompt } from "@openuidev/assistant-ui/ai-sdk";
|
|
69
|
+
import { Thread } from "@/components/assistant-ui/thread";
|
|
70
|
+
|
|
71
|
+
export default function Home() {
|
|
72
|
+
const runtime = useChatRuntime({
|
|
73
|
+
sendAutomaticallyWhen: shouldContinueAfterOpenUIPrompt,
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
const config = AuiConfig({
|
|
77
|
+
tools: Tools({ toolkit: openuiIntegration.toolkit }),
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
return (
|
|
81
|
+
<AssistantRuntimeProvider config={config} runtime={runtime}>
|
|
82
|
+
<OpenUIInstructions />
|
|
83
|
+
<Thread />
|
|
84
|
+
</AssistantRuntimeProvider>
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
`sendAutomaticallyWhen` is the continuation gate. OpenUI's predicate continues the run only after `prompt_openui` has received a submitted result, so a display-only `present_openui` call ends the turn instead of triggering an empty follow-up request.
|
|
90
|
+
|
|
91
|
+
<Callout type="info">
|
|
92
|
+
`sendAutomaticallyWhen` is a single slot. OpenUI's predicate is a strict refinement of `lastAssistantMessageIsCompleteWithToolCalls` (the predicate the other guides in this section use), so it replaces it cleanly when OpenUI's tools are the only ones that resume the run. If your app mixes in other tools whose flows must also resume, write one predicate that decides by tool name; a naive `||` with the generic predicate collapses to the generic predicate alone and re-enables the empty follow-up after display-only calls.
|
|
93
|
+
</Callout>
|
|
94
|
+
|
|
95
|
+
</Step>
|
|
96
|
+
|
|
97
|
+
<Step>
|
|
98
|
+
|
|
99
|
+
### Forward the tools in your API route
|
|
100
|
+
|
|
101
|
+
The default `AssistantChatTransport` forwards the registered instructions and both frontend tool schemas to the backend, so the route stays generic:
|
|
102
|
+
|
|
103
|
+
```ts title="app/api/chat/route.ts"
|
|
104
|
+
import { openai } from "@ai-sdk/openai";
|
|
105
|
+
import { frontendTools } from "@assistant-ui/react-ai-sdk";
|
|
106
|
+
import {
|
|
107
|
+
type JSONSchema7,
|
|
108
|
+
streamText,
|
|
109
|
+
convertToModelMessages,
|
|
110
|
+
type UIMessage,
|
|
111
|
+
createUIMessageStreamResponse,
|
|
112
|
+
toUIMessageStream,
|
|
113
|
+
} from "ai";
|
|
114
|
+
|
|
115
|
+
export const maxDuration = 30;
|
|
116
|
+
|
|
117
|
+
export async function POST(req: Request) {
|
|
118
|
+
const {
|
|
119
|
+
messages,
|
|
120
|
+
system,
|
|
121
|
+
tools,
|
|
122
|
+
}: {
|
|
123
|
+
messages: UIMessage[];
|
|
124
|
+
system?: string;
|
|
125
|
+
tools?: Record<string, { description?: string; parameters: JSONSchema7 }>;
|
|
126
|
+
} = await req.json();
|
|
127
|
+
|
|
128
|
+
const result = streamText({
|
|
129
|
+
model: openai("gpt-5.6-luna"),
|
|
130
|
+
messages: await convertToModelMessages(messages),
|
|
131
|
+
...(system ? { system } : {}),
|
|
132
|
+
tools: frontendTools(tools ?? {}),
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
return createUIMessageStreamResponse({
|
|
136
|
+
stream: toUIMessageStream({ stream: result.stream }),
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
</Step>
|
|
142
|
+
|
|
143
|
+
</Steps>
|
|
144
|
+
|
|
145
|
+
## Interaction and replay
|
|
146
|
+
|
|
147
|
+
When the user submits a `prompt_openui` form or choice, the integration reports the action, message, parameters, and form state through the standard human-tool `addResult`, and `sendAutomaticallyWhen` resumes the run with that result. On replay of a persisted thread, the stored result hydrates the submitted form state back into the renderer, so completed forms render as submitted instead of resetting.
|
|
148
|
+
|
|
149
|
+
<Callout type="tip">
|
|
150
|
+
The core integration is runtime-agnostic: the toolkit, renderers, and instructions work with any assistant-ui runtime that forwards tool schemas and results. Only the `shouldContinueAfterOpenUIPrompt` helper on the `/ai-sdk` subpath is AI SDK-specific.
|
|
151
|
+
</Callout>
|
|
152
|
+
|
|
153
|
+
## Customization
|
|
154
|
+
|
|
155
|
+
`createOpenUIIntegration` keeps a custom component library, tool names, and renderer options aligned across the toolkit and the instructions:
|
|
156
|
+
|
|
157
|
+
```tsx
|
|
158
|
+
import { createOpenUIIntegration } from "@openuidev/assistant-ui";
|
|
159
|
+
import { library } from "./library";
|
|
160
|
+
|
|
161
|
+
const openui = createOpenUIIntegration({
|
|
162
|
+
library,
|
|
163
|
+
presentToolName: "show_panel",
|
|
164
|
+
promptToolName: "ask_panel",
|
|
165
|
+
});
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
The result exposes `toolkit`, `instructions`, and the resolved `toolNames`. See [OpenUI's integration reference](https://www.openui.com/docs/api-reference/assistant-ui) for the full option surface, including custom descriptions, prompt options, renderer props, and error handling.
|
|
169
|
+
|
|
170
|
+
## Related
|
|
171
|
+
|
|
172
|
+
- [`examples/with-openui`](https://github.com/assistant-ui/assistant-ui/tree/main/examples/with-openui): the runnable setup from this page
|
|
173
|
+
- [OpenUI assistant-ui integration reference](https://www.openui.com/docs/api-reference/assistant-ui): the canonical package documentation
|
|
174
|
+
- [Generative UI](/docs/tools/generative-ui): the first-party `present` tool this integration sits alongside
|
|
175
|
+
- [Tool UI](/docs/tools/tool-ui): the lifecycle both OpenUI tools build on
|
|
@@ -21,8 +21,7 @@ Tool UIs in assistant-ui allow you to create custom interfaces that appear when
|
|
|
21
21
|
|
|
22
22
|
This guide demonstrates building tool UIs with the **Vercel AI SDK**.
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
see the [Generative UI primitive guide](/docs/tools/generative-ui).
|
|
24
|
+
To let the model compose UI from a vocabulary instead of binding one component per tool, see [Generative UI](/docs/tools/generative-ui).
|
|
26
25
|
|
|
27
26
|
## Creating Tool UIs
|
|
28
27
|
|
|
@@ -69,15 +68,15 @@ export default defineToolkit({
|
|
|
69
68
|
```
|
|
70
69
|
|
|
71
70
|
```tsx title="app/MyRuntimeProvider.tsx"
|
|
72
|
-
import { AssistantRuntimeProvider,
|
|
71
|
+
import { AssistantRuntimeProvider, AuiConfig, Tools } from "@assistant-ui/react";
|
|
73
72
|
import { useChatRuntime } from "@assistant-ui/react-ai-sdk";
|
|
74
73
|
import toolkit from "./toolkit";
|
|
75
74
|
|
|
76
75
|
function MyRuntimeProvider({ children }: { children: React.ReactNode }) {
|
|
77
76
|
const runtime = useChatRuntime();
|
|
78
|
-
const
|
|
77
|
+
const config = AuiConfig({ tools: Tools({ toolkit }) });
|
|
79
78
|
return (
|
|
80
|
-
<AssistantRuntimeProvider
|
|
79
|
+
<AssistantRuntimeProvider runtime={runtime} config={config}>
|
|
81
80
|
{children}
|
|
82
81
|
</AssistantRuntimeProvider>
|
|
83
82
|
);
|
|
@@ -190,10 +189,9 @@ const toolkit = defineToolkit({
|
|
|
190
189
|
});
|
|
191
190
|
|
|
192
191
|
function App({ runtime }: { runtime: AssistantRuntime }) {
|
|
193
|
-
const
|
|
194
|
-
|
|
192
|
+
const config = AuiConfig({ tools: Tools({ toolkit }) });
|
|
195
193
|
return (
|
|
196
|
-
<AssistantRuntimeProvider
|
|
194
|
+
<AssistantRuntimeProvider runtime={runtime} config={config}>
|
|
197
195
|
<Thread />
|
|
198
196
|
</AssistantRuntimeProvider>
|
|
199
197
|
);
|
|
@@ -215,7 +213,7 @@ export async function POST(req: Request) {
|
|
|
215
213
|
const { messages } = await req.json();
|
|
216
214
|
|
|
217
215
|
const result = streamText({
|
|
218
|
-
model: openai("gpt-5.
|
|
216
|
+
model: openai("gpt-5.6-luna"),
|
|
219
217
|
messages: await convertToModelMessages(messages),
|
|
220
218
|
tools: {
|
|
221
219
|
getWeather: tool({
|
|
@@ -331,19 +329,21 @@ export function useAnalyzeDataToolkit(theme: "light" | "dark") {
|
|
|
331
329
|
```
|
|
332
330
|
|
|
333
331
|
```tsx title="DynamicToolUI.tsx"
|
|
334
|
-
import { AuiProvider, Tools, useAui } from "@assistant-ui/react";
|
|
332
|
+
import { AuiConfig, AuiProvider, Tools, useAui } from "@assistant-ui/react";
|
|
335
333
|
import { useState } from "react";
|
|
336
334
|
import { useAnalyzeDataToolkit } from "./analyze-data-toolkit";
|
|
337
335
|
|
|
338
336
|
function DynamicToolUI({ children }: { children: React.ReactNode }) {
|
|
339
337
|
const [theme] = useState<"light" | "dark">("light");
|
|
340
338
|
const toolkit = useAnalyzeDataToolkit(theme);
|
|
339
|
+
const aui = useAui();
|
|
340
|
+
const config = AuiConfig({ tools: Tools({ toolkit }) });
|
|
341
341
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
342
|
+
return (
|
|
343
|
+
<AuiProvider extends={aui} config={config}>
|
|
344
|
+
{children}
|
|
345
|
+
</AuiProvider>
|
|
346
|
+
);
|
|
347
347
|
}
|
|
348
348
|
```
|
|
349
349
|
|
|
@@ -390,18 +390,16 @@ export function useInventoryToolkit(productId: string, productName: string) {
|
|
|
390
390
|
```
|
|
391
391
|
|
|
392
392
|
```tsx title="ProductPage.tsx"
|
|
393
|
-
import { AuiProvider, Tools, useAui } from "@assistant-ui/react";
|
|
393
|
+
import { AuiConfig, AuiProvider, Tools, useAui } from "@assistant-ui/react";
|
|
394
394
|
import { useInventoryToolkit } from "./inventory-toolkit";
|
|
395
395
|
|
|
396
396
|
function ProductPage({ productId, productName }) {
|
|
397
397
|
const toolkit = useInventoryToolkit(productId, productName);
|
|
398
|
-
|
|
399
|
-
const
|
|
400
|
-
tools: Tools({ toolkit }),
|
|
401
|
-
});
|
|
398
|
+
const aui = useAui();
|
|
399
|
+
const config = AuiConfig({ tools: Tools({ toolkit }) });
|
|
402
400
|
|
|
403
401
|
return (
|
|
404
|
-
<AuiProvider
|
|
402
|
+
<AuiProvider extends={aui} config={config}>
|
|
405
403
|
<div>Product details...</div>
|
|
406
404
|
</AuiProvider>
|
|
407
405
|
);
|
|
@@ -942,15 +940,20 @@ export function useHeavyComputationToolkit() {
|
|
|
942
940
|
```
|
|
943
941
|
|
|
944
942
|
```tsx title="HeavyComputationToolProvider.tsx"
|
|
945
|
-
import { AuiProvider, Tools, useAui } from "@assistant-ui/react";
|
|
943
|
+
import { AuiConfig, AuiProvider, Tools, useAui } from "@assistant-ui/react";
|
|
946
944
|
import type { ReactNode } from "react";
|
|
947
945
|
import { useHeavyComputationToolkit } from "./heavy-computation-toolkit";
|
|
948
946
|
|
|
949
947
|
function HeavyComputationToolProvider({ children }: { children: ReactNode }) {
|
|
950
948
|
const toolkit = useHeavyComputationToolkit();
|
|
951
|
-
const aui = useAui(
|
|
949
|
+
const aui = useAui();
|
|
950
|
+
const config = AuiConfig({ tools: Tools({ toolkit }) });
|
|
952
951
|
|
|
953
|
-
return
|
|
952
|
+
return (
|
|
953
|
+
<AuiProvider extends={aui} config={config}>
|
|
954
|
+
{children}
|
|
955
|
+
</AuiProvider>
|
|
956
|
+
);
|
|
954
957
|
}
|
|
955
958
|
```
|
|
956
959
|
|
|
@@ -15,14 +15,18 @@ Both flow through one connection lifecycle, one persisted state surface, and one
|
|
|
15
15
|
## How it works
|
|
16
16
|
|
|
17
17
|
```
|
|
18
|
-
|
|
18
|
+
AuiConfig({ mcp: McpManagerResource({ connectors }) })
|
|
19
19
|
│
|
|
20
20
|
├─ Resource — connection lifecycle, server lookup, OAuth/bearer auth
|
|
21
21
|
├─ Auto-mounts the modelContext scope when no chat runtime provides one
|
|
22
22
|
└─ Registers connected tools as frontend tools — your chat sees them automatically
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
-
The manager is a single resource. Mount it with `
|
|
25
|
+
The manager is a single resource. Mount it with `AuiProvider` like any other scope. OAuth (PKCE + RFC 7591 dynamic client registration), bearer, and "no auth" are first-class. Token refresh runs inside the MCP SDK on 401; this package mediates persistence and the redirect step.
|
|
26
|
+
|
|
27
|
+
<Callout type="info">
|
|
28
|
+
The [2026-07-28 spec revision](https://modelcontextprotocol.io/specification/2026-07-28/changelog) deprecates RFC 7591 dynamic client registration in favor of [Client ID Metadata Documents](https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization/client-registration#client-id-metadata-documents), which clients should prefer over DCR when the authorization server advertises `client_id_metadata_document_supported`. Dynamic client registration remains available for backwards compatibility with authorization servers that do not support CIMD, and the spec's deprecation policy sets a minimum twelve-month window before removal, so the flow described here keeps working. Against a CIMD-only authorization server that exposes no `registration_endpoint`, supply a pre-registered [`clientId`](#auth) instead.
|
|
29
|
+
</Callout>
|
|
26
30
|
|
|
27
31
|
## Setup
|
|
28
32
|
|
|
@@ -38,12 +42,12 @@ The manager is a single resource. Mount it with `useAui` like any other scope. O
|
|
|
38
42
|
|
|
39
43
|
### Mount the manager
|
|
40
44
|
|
|
41
|
-
Declare your connectors and provide the `mcp` scope
|
|
45
|
+
Declare your connectors and provide the `mcp` scope via `AuiProvider`. No imperative hooks:
|
|
42
46
|
|
|
43
47
|
```tsx title="app/providers.tsx"
|
|
44
48
|
"use client";
|
|
45
49
|
|
|
46
|
-
import { AuiProvider, useAui } from "@assistant-ui/react";
|
|
50
|
+
import { AuiConfig, AuiProvider, useAui } from "@assistant-ui/react";
|
|
47
51
|
import { McpManagerResource, defineConnector } from "@assistant-ui/react-mcp";
|
|
48
52
|
|
|
49
53
|
const connectors = [
|
|
@@ -64,13 +68,18 @@ const connectors = [
|
|
|
64
68
|
];
|
|
65
69
|
|
|
66
70
|
export function Providers({ children }: { children: React.ReactNode }) {
|
|
67
|
-
const aui = useAui(
|
|
71
|
+
const aui = useAui();
|
|
72
|
+
const config = AuiConfig({
|
|
68
73
|
mcp: McpManagerResource({
|
|
69
74
|
connectors,
|
|
70
75
|
connectionTimeout: 15_000,
|
|
71
76
|
}),
|
|
72
77
|
});
|
|
73
|
-
return
|
|
78
|
+
return (
|
|
79
|
+
<AuiProvider extends={aui} config={config}>
|
|
80
|
+
{children}
|
|
81
|
+
</AuiProvider>
|
|
82
|
+
);
|
|
74
83
|
}
|
|
75
84
|
```
|
|
76
85
|
|
|
@@ -297,7 +306,7 @@ All persisted state — custom server records, OAuth tokens, PKCE verifiers, DCR
|
|
|
297
306
|
```tsx
|
|
298
307
|
import { McpManagerResource, McpCustomStorage } from "@assistant-ui/react-mcp";
|
|
299
308
|
|
|
300
|
-
|
|
309
|
+
AuiConfig({
|
|
301
310
|
mcp: McpManagerResource({
|
|
302
311
|
connectors,
|
|
303
312
|
storage: McpCustomStorage({
|
|
@@ -336,7 +345,7 @@ Three modes, declared per-connector or per-custom-record:
|
|
|
336
345
|
}
|
|
337
346
|
```
|
|
338
347
|
|
|
339
|
-
The OAuth provider implements the MCP SDK's `OAuthClientProvider`. The SDK handles discovery (RFC 8414), DCR (RFC 7591), PKCE, token exchange, and refresh; this package mediates `MCPStorage` reads/writes and the redirect step. The server id is embedded in the OAuth `state` parameter so a single `/mcp/callback` route knows which server to complete.
|
|
348
|
+
The OAuth provider implements the MCP SDK's `OAuthClientProvider`. The SDK handles discovery (RFC 8414), DCR (RFC 7591 — [deprecated in favor of CIMD](#how-it-works) but still supported), PKCE, token exchange, and refresh; this package mediates `MCPStorage` reads/writes and the redirect step. The server id is embedded in the OAuth `state` parameter so a single `/mcp/callback` route knows which server to complete.
|
|
340
349
|
|
|
341
350
|
## State & methods
|
|
342
351
|
|