@assistant-ui/mcp-docs-server 0.1.36 → 0.1.38
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/with-ai-sdk-v6.md +2 -2
- package/.docs/organized/code-examples/with-artifacts.md +2 -2
- package/.docs/organized/code-examples/with-chain-of-thought.md +2 -2
- package/.docs/organized/code-examples/with-cloud-standalone.md +2 -2
- package/.docs/organized/code-examples/with-cloud.md +2 -2
- package/.docs/organized/code-examples/with-custom-thread-list.md +2 -2
- package/.docs/organized/code-examples/with-elevenlabs-conversational.md +5 -5
- package/.docs/organized/code-examples/with-elevenlabs-scribe.md +5 -5
- package/.docs/organized/code-examples/with-eve.md +1 -1
- package/.docs/organized/code-examples/with-expo.md +6 -6
- package/.docs/organized/code-examples/with-ffmpeg.md +2 -2
- package/.docs/organized/code-examples/with-generative-ui.md +3 -3
- package/.docs/organized/code-examples/with-google-adk.md +1 -1
- package/.docs/organized/code-examples/with-image-generation.md +2 -2
- package/.docs/organized/code-examples/with-interactables.md +2 -2
- package/.docs/organized/code-examples/with-langchain.md +2 -2
- package/.docs/organized/code-examples/with-langgraph.md +2 -2
- package/.docs/organized/code-examples/with-livekit.md +5 -5
- package/.docs/organized/code-examples/with-mcp.md +17 -8
- package/.docs/organized/code-examples/with-pi.md +1 -1
- package/.docs/organized/code-examples/with-react-hook-form.md +2 -2
- package/.docs/organized/code-examples/with-react-ink-web.md +1 -1
- package/.docs/organized/code-examples/with-react-router.md +2 -2
- package/.docs/organized/code-examples/with-resumable-stream.md +3 -3
- package/.docs/organized/code-examples/with-tanstack.md +2 -2
- package/.docs/raw/docs/(docs)/cli.mdx +1 -1
- package/.docs/raw/docs/cloud/langgraph.mdx +1 -1
- package/.docs/raw/docs/integrations/frameworks/ai-sdk.mdx +3 -3
- package/.docs/raw/docs/integrations/index.mdx +1 -1
- package/.docs/raw/docs/integrations/observability/langsmith.mdx +2 -2
- package/.docs/raw/docs/migrations/react-langgraph-v0-7.mdx +2 -2
- package/.docs/raw/docs/primitives/thread-list.mdx +30 -6
- package/.docs/raw/docs/runtimes/a2a/quickstart.mdx +1 -1
- package/.docs/raw/docs/runtimes/ag-ui/quickstart.mdx +1 -1
- package/.docs/raw/docs/runtimes/ag-ui/runtime-options.mdx +3 -1
- package/.docs/raw/docs/runtimes/ai-sdk/v6.mdx +1 -1
- package/.docs/raw/docs/runtimes/google-adk/quickstart.mdx +1 -1
- package/.docs/raw/docs/runtimes/langchain.mdx +2 -2
- package/.docs/raw/docs/runtimes/opencode/hooks.mdx +1 -1
- package/.docs/raw/docs/tools/defining-tools.mdx +5 -0
- package/.docs/raw/docs/tools/generative-ui.mdx +37 -0
- package/.docs/raw/docs/tools/mcp-apps.mdx +12 -3
- package/.docs/raw/docs/tools/mcp.mdx +5 -0
- package/.docs/raw/docs/tools/user-managed-mcp.mdx +17 -3
- package/.docs/raw/docs/ui/follow-up-suggestions.mdx +80 -0
- package/.docs/raw/docs/ui/model-selector.mdx +38 -5
- package/README.md +1 -1
- package/dist/constants.d.ts +2 -1
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +2 -1
- package/dist/constants.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -1
- package/dist/prepare-docs/copy-raw.d.ts.map +1 -1
- package/dist/prepare-docs/copy-raw.js +0 -4
- package/dist/prepare-docs/copy-raw.js.map +1 -1
- package/dist/tools/docs.d.ts.map +1 -1
- package/dist/tools/docs.js +18 -6
- package/dist/tools/docs.js.map +1 -1
- package/dist/tools/examples.d.ts +3 -1
- package/dist/tools/examples.d.ts.map +1 -1
- package/dist/tools/examples.js +1 -1
- package/dist/tools/examples.js.map +1 -1
- package/dist/tools/resources.d.ts +7 -0
- package/dist/tools/resources.d.ts.map +1 -0
- package/dist/tools/resources.js +74 -0
- package/dist/tools/resources.js.map +1 -0
- package/dist/tools/search.d.ts +33 -0
- package/dist/tools/search.d.ts.map +1 -0
- package/dist/tools/search.js +39 -0
- package/dist/tools/search.js.map +1 -0
- package/dist/tools/tests/test-setup.d.ts.map +1 -1
- package/dist/tools/tests/test-setup.js +3 -1
- package/dist/tools/tests/test-setup.js.map +1 -1
- package/dist/utils/mdx.d.ts +2 -1
- package/dist/utils/mdx.d.ts.map +1 -1
- package/dist/utils/mdx.js +19 -2
- package/dist/utils/mdx.js.map +1 -1
- package/dist/utils/paths.d.ts +2 -1
- package/dist/utils/paths.d.ts.map +1 -1
- package/dist/utils/paths.js +18 -1
- package/dist/utils/paths.js.map +1 -1
- package/dist/utils/search.d.ts +10 -0
- package/dist/utils/search.d.ts.map +1 -0
- package/dist/utils/search.js +97 -0
- package/dist/utils/search.js.map +1 -0
- package/package.json +2 -2
- package/src/constants.ts +2 -0
- package/src/index.ts +14 -0
- package/src/prepare-docs/copy-raw.ts +0 -5
- package/src/tools/docs.ts +30 -4
- package/src/tools/examples.ts +4 -2
- package/src/tools/resources.ts +114 -0
- package/src/tools/search.ts +46 -0
- package/src/tools/tests/completions.test.ts +46 -0
- package/src/tools/tests/directory-size-cap.test.ts +50 -0
- package/src/tools/tests/mcp-protocol.test.ts +12 -1
- package/src/tools/tests/resources.test.ts +102 -0
- package/src/tools/tests/search.test.ts +37 -0
- package/src/tools/tests/test-setup.ts +2 -0
- package/src/utils/mdx.ts +21 -1
- package/src/utils/paths.ts +22 -0
- package/src/utils/search.ts +131 -0
- package/.docs/raw/blog/2024-07-29-hello/index.mdx +0 -64
- package/.docs/raw/blog/2024-09-11/index.mdx +0 -10
- package/.docs/raw/blog/2024-12-15/index.mdx +0 -10
- package/.docs/raw/blog/2025-01-31-changelog/index.mdx +0 -127
- package/.docs/raw/blog/2026-03-launch-week/index.mdx +0 -258
|
@@ -38,12 +38,12 @@ function MyThreadList() {
|
|
|
38
38
|
|
|
39
39
|
function ThreadListItem() {
|
|
40
40
|
return (
|
|
41
|
-
<ThreadListItemPrimitive.Root className="group flex h-9 items-center rounded-lg hover:bg-muted data-active:bg-muted">
|
|
42
|
-
<ThreadListItemPrimitive.Trigger className="flex-1 truncate px-3 text-sm">
|
|
41
|
+
<ThreadListItemPrimitive.Root className="group relative flex h-9 items-center rounded-lg hover:bg-muted data-active:bg-muted has-focus-visible:bg-muted">
|
|
42
|
+
<ThreadListItemPrimitive.Trigger className="min-w-0 flex-1 truncate px-3 text-sm outline-none">
|
|
43
43
|
<ThreadListItemPrimitive.Title fallback="New Chat" />
|
|
44
44
|
</ThreadListItemPrimitive.Trigger>
|
|
45
|
-
<ThreadListItemMorePrimitive.Root>
|
|
46
|
-
<ThreadListItemMorePrimitive.Trigger className="
|
|
45
|
+
<ThreadListItemMorePrimitive.Root sharedFocusGroup>
|
|
46
|
+
<ThreadListItemMorePrimitive.Trigger className="absolute end-1.5 top-1/2 size-7 -translate-y-1/2 rounded-md opacity-0 group-hover:opacity-100 group-has-focus-visible:opacity-100 data-[state=open]:opacity-100">
|
|
47
47
|
<MoreHorizontalIcon className="size-4" />
|
|
48
48
|
</ThreadListItemMorePrimitive.Trigger>
|
|
49
49
|
<ThreadListItemMorePrimitive.Content className="rounded-md border bg-popover p-1 shadow-md">
|
|
@@ -118,6 +118,21 @@ Both `ThreadListPrimitive.New` and `ThreadListItemPrimitive.Root` get a `data-ac
|
|
|
118
118
|
|
|
119
119
|
The `New` button gets `data-active` when the user is on a fresh, unsaved thread.
|
|
120
120
|
|
|
121
|
+
### Keyboard Navigation
|
|
122
|
+
|
|
123
|
+
Every item stays a native Tab stop, and arrow keys are layered on top. Up/Down move between items and Right focuses an item's `More` button (Left/Right are mirrored in RTL). This is built into the primitives — no prop is required.
|
|
124
|
+
|
|
125
|
+
To fold the `More` menu into the same navigation, opt it in with `sharedFocusGroup`:
|
|
126
|
+
|
|
127
|
+
```tsx
|
|
128
|
+
<ThreadListItemMorePrimitive.Root sharedFocusGroup>
|
|
129
|
+
{/* Right opens the menu from the trigger; Left/Escape close it and
|
|
130
|
+
return focus to the trigger, keeping the highlight continuous. */}
|
|
131
|
+
</ThreadListItemMorePrimitive.Root>
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
`sharedFocusGroup` joins the menu to the list's focus group, so its trigger and the open menu act as one keyboard-navigable unit: Right opens it and Left/Escape close it, synchronously restoring focus to the trigger so a `group-has-focus-visible` highlight never flickers. Enabling it forces the menu non-modal, because a focus trap and a shared focus group are mutually exclusive — the trap keeps focus inside the menu, the shared group lets it move out across the boundary. Without `sharedFocusGroup` the menu keeps its standard Radix `DropdownMenu` keyboard behavior (modal by default), so menus you already render are unchanged. Our assistant-ui [thread-list](/docs/ui/thread-list) registry component sets `sharedFocusGroup` for you.
|
|
135
|
+
|
|
121
136
|
### Items Iterator
|
|
122
137
|
|
|
123
138
|
`ThreadListPrimitive.Items` now prefers a children render function, similar to `ThreadPrimitive.Messages`:
|
|
@@ -168,6 +183,15 @@ The canonical pattern composes `ThreadListItemPrimitive.Archive asChild` with `T
|
|
|
168
183
|
|
|
169
184
|
`Archive` provides the click handler and disabled logic. `Item` provides the menu item behavior and styling. `asChild` merges them into a single element.
|
|
170
185
|
|
|
186
|
+
## Accessibility
|
|
187
|
+
|
|
188
|
+
The thread list leans on native button semantics and Radix's `DropdownMenu`; the arrow-key navigation is layered on top as a convenience, not a requirement.
|
|
189
|
+
|
|
190
|
+
- Each `ThreadListItemPrimitive.Trigger` is a native `<button>` and its own Tab stop, so the whole list is reachable with <Kbd>Tab</Kbd> alone. The arrow keys (see [Keyboard Navigation](#keyboard-navigation)) speed traversal up, but nothing depends on them.
|
|
191
|
+
- The item representing the current thread sets `aria-current="true"` (alongside `data-active`) on `ThreadListItemPrimitive.Root`, so assistive tech announces which conversation is open.
|
|
192
|
+
- The `More` trigger exposes `aria-haspopup="menu"`, and its panel is a Radix `role="menu"` with `role="menuitem"` children, so screen readers announce it as a menu and the arrow keys cycle its items.
|
|
193
|
+
- With `sharedFocusGroup`, the `More` menu is non-modal and joins the list's focus group: opening and closing it move focus synchronously between the trigger and the menu, so keyboard focus is never dropped and the `group-has-focus-visible` highlight never flickers. Without it, the menu keeps Radix's default modal focus trap.
|
|
194
|
+
|
|
171
195
|
## Parts
|
|
172
196
|
|
|
173
197
|
### ThreadListPrimitive
|
|
@@ -319,10 +343,10 @@ Button that deletes the current thread item. Renders a `<button>` element unless
|
|
|
319
343
|
|
|
320
344
|
#### Root
|
|
321
345
|
|
|
322
|
-
Root container for the overflow menu primitives.
|
|
346
|
+
Root container for the overflow menu primitives. Pass `sharedFocusGroup` to fold the menu into the list's arrow-key navigation (see [Keyboard Navigation](#keyboard-navigation)); doing so forces it non-modal. Without it the menu honors the `modal` prop, defaulting to modal like Radix's `DropdownMenu`.
|
|
323
347
|
|
|
324
348
|
```tsx
|
|
325
|
-
<ThreadListItemMorePrimitive.Root>
|
|
349
|
+
<ThreadListItemMorePrimitive.Root sharedFocusGroup>
|
|
326
350
|
<ThreadListItemMorePrimitive.Trigger>More</ThreadListItemMorePrimitive.Trigger>
|
|
327
351
|
</ThreadListItemMorePrimitive.Root>
|
|
328
352
|
```
|
|
@@ -3,7 +3,7 @@ title: Quickstart
|
|
|
3
3
|
description: Minimal runtime and Thread setup against an A2A server.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
Three steps to a working chat against an A2A server. Assumes you have already installed the package and have an A2A v1.0 server reachable; if not, start at [overview](/docs/runtimes/a2a).
|
|
6
|
+
Three steps to a working chat against an A2A server. Assumes you have already installed the package and have an A2A v1.0 server reachable; if not, start at [overview](/docs/runtimes/a2a/overview).
|
|
7
7
|
|
|
8
8
|
<Steps>
|
|
9
9
|
<Step>
|
|
@@ -3,7 +3,7 @@ title: Quickstart
|
|
|
3
3
|
description: Minimal HttpAgent + useAgUiRuntime setup against an AG-UI server.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
Three steps to a working chat against an AG-UI agent. Assumes you have already installed the package and have an AG-UI server reachable; if not, start at [overview](/docs/runtimes/ag-ui).
|
|
6
|
+
Three steps to a working chat against an AG-UI agent. Assumes you have already installed the package and have an AG-UI server reachable; if not, start at [overview](/docs/runtimes/ag-ui/overview).
|
|
7
7
|
|
|
8
8
|
<Steps>
|
|
9
9
|
<Step>
|
|
@@ -70,6 +70,8 @@ time, the same way a live run never stores them.
|
|
|
70
70
|
|
|
71
71
|
An assistant message whose tool call has no matching tool result is reconstructed with `requires-action` status, the same status the runtime derives for a pending tool call, so a reloaded human-in-the-loop call (for example an `ask_user` tool) is actionable rather than stuck. This matches how every other external-store runtime surfaces a pending tool call on reload. The AG-UI wire snapshot carries no run outcome, so a tool call that a successful run intentionally left without a result is also surfaced as actionable.
|
|
72
72
|
|
|
73
|
+
Interrupts are restored when your backend persists them on the assistant message. The AG-UI message body has no interrupt field, so persist the runtime's own `metadata.custom.agui.interrupts` array alongside the message; `fromAgUiMessages` reads it back, reconstructs `requires-action` / `interrupt` status, and re-attaches the metadata, so `getPendingInterrupts`, `useAgUiInterrupts`, and `submitInterruptResponses` work on reload. When both a pending tool call and an interrupt are present on the same message, interrupt status wins. Without the persisted array, interrupt state cannot be reconstructed.
|
|
74
|
+
|
|
73
75
|
## Thread list (experimental)
|
|
74
76
|
|
|
75
77
|
<Callout type="warn">
|
|
@@ -199,7 +201,7 @@ The runtime parses the AG-UI event stream and maps each event type to assistant-
|
|
|
199
201
|
icon={<AguiIcon width={20} height={20} />}
|
|
200
202
|
title="AG-UI overview"
|
|
201
203
|
description="What AG-UI is and when to pick it."
|
|
202
|
-
href="/docs/runtimes/ag-ui"
|
|
204
|
+
href="/docs/runtimes/ag-ui/overview"
|
|
203
205
|
/>
|
|
204
206
|
<Card
|
|
205
207
|
title="Quickstart"
|
|
@@ -3,7 +3,7 @@ title: AI SDK v6
|
|
|
3
3
|
description: Integrate Vercel AI SDK v6 with assistant-ui for streaming chat.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
Current-version integration. Requires `ai@^6` and `@ai-sdk/react@^3`. For older versions see the [overview](/docs/runtimes/ai-sdk).
|
|
6
|
+
Current-version integration. Requires `ai@^6` and `@ai-sdk/react@^3`. For older versions see the [overview](/docs/runtimes/ai-sdk/overview).
|
|
7
7
|
|
|
8
8
|
## Quickstart
|
|
9
9
|
|
|
@@ -3,7 +3,7 @@ title: Quickstart
|
|
|
3
3
|
description: Minimal API route and client setup with createAdkApiRoute.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
Four steps to a working ADK chat. Assumes you have already installed the package and have ADK ready on the server side; if not, start at [overview](/docs/runtimes/google-adk).
|
|
6
|
+
Four steps to a working ADK chat. Assumes you have already installed the package and have ADK ready on the server side; if not, start at [overview](/docs/runtimes/google-adk/overview).
|
|
7
7
|
|
|
8
8
|
<Steps>
|
|
9
9
|
<Step>
|
|
@@ -5,7 +5,7 @@ description: Use LangChain's useStream hook with a React chat UI through assista
|
|
|
5
5
|
|
|
6
6
|
import { LangGraphIcon } from "@/components/icons/langgraph";
|
|
7
7
|
|
|
8
|
-
`@assistant-ui/react-langchain` wraps [`useStream`](https://docs.langchain.com/oss/javascript/langgraph-sdk/react-stream) from `@langchain/react` and exposes it as an assistant-ui runtime. It targets the same backend as [`@assistant-ui/react-langgraph`](/docs/runtimes/langgraph) (LangGraph Cloud) but at a higher level, delegating stream plumbing to the upstream hook.
|
|
8
|
+
`@assistant-ui/react-langchain` wraps [`useStream`](https://docs.langchain.com/oss/javascript/langgraph-sdk/react-stream) from `@langchain/react` and exposes it as an assistant-ui runtime. It targets the same backend as [`@assistant-ui/react-langgraph`](/docs/runtimes/langgraph/overview) (LangGraph Cloud) but at a higher level, delegating stream plumbing to the upstream hook.
|
|
9
9
|
|
|
10
10
|
## When to use it
|
|
11
11
|
|
|
@@ -891,7 +891,7 @@ Regenerate works without configuration. Clicking regenerate resolves the server
|
|
|
891
891
|
icon={<LangGraphIcon width={20} height={20} className="text-[#1C3C3C] dark:text-[#5b9595]" />}
|
|
892
892
|
title="LangGraph"
|
|
893
893
|
description="The original LangGraph adapter, built on the raw SDK."
|
|
894
|
-
href="/docs/runtimes/langgraph"
|
|
894
|
+
href="/docs/runtimes/langgraph/overview"
|
|
895
895
|
/>
|
|
896
896
|
<Card
|
|
897
897
|
title="ExternalStoreRuntime"
|
|
@@ -175,7 +175,7 @@ These are only needed for advanced cases; most apps should use `useOpenCodeRunti
|
|
|
175
175
|
icon={<OpenCodeIcon width={20} height={20} />}
|
|
176
176
|
title="OpenCode overview"
|
|
177
177
|
description="What OpenCode is and when to pick it."
|
|
178
|
-
href="/docs/runtimes/opencode"
|
|
178
|
+
href="/docs/runtimes/opencode/overview"
|
|
179
179
|
/>
|
|
180
180
|
<Card
|
|
181
181
|
title="Quickstart"
|
|
@@ -427,6 +427,11 @@ The compiler checks static tool names across inline entries and compiler-visible
|
|
|
427
427
|
spreads. If two fragments define the same tool name, the build warns that
|
|
428
428
|
JavaScript object spread will keep the later tool definition.
|
|
429
429
|
|
|
430
|
+
If the compiler reports that `tool "weather" cannot be makeTool()`, that entry
|
|
431
|
+
came from an opaque factory call. Rewrite it as an inline tool object, or spread
|
|
432
|
+
a compiler-visible `defineToolkit(...)` / `defineMcpToolkit(...)` fragment
|
|
433
|
+
instead.
|
|
434
|
+
|
|
430
435
|
### Add MCP server tools
|
|
431
436
|
|
|
432
437
|
`defineMcpToolkit` exposes tools from an MCP server. For an MCP-only toolkit, export it directly:
|
|
@@ -166,6 +166,43 @@ type GenerativeUISpec = {
|
|
|
166
166
|
The spec is plain JSON — easy for any agent to emit, and easy to validate
|
|
167
167
|
on the server before delivery.
|
|
168
168
|
|
|
169
|
+
## Actions with `JSONGenerativeUI`
|
|
170
|
+
|
|
171
|
+
When you expose a component library through `new JSONGenerativeUI(...)`, pass an
|
|
172
|
+
action registry to let interactive nodes call back into your app. This path uses
|
|
173
|
+
the flat `{ "$type": ... }` node shape; the model puts an `$action` object on
|
|
174
|
+
the node, and its `type` is matched against your registered handlers.
|
|
175
|
+
|
|
176
|
+
```tsx
|
|
177
|
+
import {
|
|
178
|
+
JSONGenerativeUI,
|
|
179
|
+
createActionRegistry,
|
|
180
|
+
defaultGenerativeUILibrary,
|
|
181
|
+
} from "@assistant-ui/react-generative-ui";
|
|
182
|
+
|
|
183
|
+
const actions = createActionRegistry({
|
|
184
|
+
purchase: async ({ payload }) => {
|
|
185
|
+
await checkout(payload);
|
|
186
|
+
},
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
const generative = new JSONGenerativeUI({
|
|
190
|
+
library: defaultGenerativeUILibrary,
|
|
191
|
+
actions,
|
|
192
|
+
});
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
```json
|
|
196
|
+
{
|
|
197
|
+
"$type": "Button",
|
|
198
|
+
"label": "Buy",
|
|
199
|
+
"$action": { "type": "purchase", "sku": "pro-plan" }
|
|
200
|
+
}
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
`Select`, `Input`, and `DatePicker` add the user's value as `$input` when they
|
|
204
|
+
fire the action. Unknown action types are ignored and warn in development.
|
|
205
|
+
|
|
169
206
|
## Streaming
|
|
170
207
|
|
|
171
208
|
When a message contains native `generative-ui` parts whose `spec` updates
|
|
@@ -24,6 +24,12 @@ Capability presence is determined at mount time by which handlers you provide. U
|
|
|
24
24
|
|
|
25
25
|
The renderer talks to a backend route you expose — the MCP client lives server-side so credentials and transport stay out of the browser. The route receives `{ method, params }` POSTs and dispatches to your MCP client.
|
|
26
26
|
|
|
27
|
+
### Install the MCP client
|
|
28
|
+
|
|
29
|
+
Install the AI SDK MCP client package used by the route handler:
|
|
30
|
+
|
|
31
|
+
<InstallCommand npm={["@ai-sdk/mcp"]} />
|
|
32
|
+
|
|
27
33
|
### Client
|
|
28
34
|
|
|
29
35
|
Compose `McpAppRenderer({...})` into your `Tools` resource. Provide `host.url` pointing at your route. Any tool-call part carrying `mcp.app` metadata renders the MCP App widget automatically.
|
|
@@ -61,12 +67,15 @@ The route accepts `POST` requests with `{ method, params }` JSON bodies. Dispatc
|
|
|
61
67
|
|
|
62
68
|
```ts
|
|
63
69
|
// app/api/mcp-apps/route.ts
|
|
64
|
-
import {
|
|
70
|
+
import { createMCPClient } from "@ai-sdk/mcp";
|
|
65
71
|
|
|
66
|
-
let clientPromise: ReturnType<typeof
|
|
72
|
+
let clientPromise: ReturnType<typeof createMCPClient> | undefined;
|
|
67
73
|
const getClient = () => {
|
|
68
|
-
clientPromise ??=
|
|
74
|
+
clientPromise ??= createMCPClient({
|
|
69
75
|
transport: { type: "sse", url: process.env.MCP_SERVER_URL! },
|
|
76
|
+
}).catch((error) => {
|
|
77
|
+
clientPromise = undefined;
|
|
78
|
+
throw error;
|
|
70
79
|
});
|
|
71
80
|
return clientPromise;
|
|
72
81
|
};
|
|
@@ -93,6 +93,7 @@ export default defineToolkit({
|
|
|
93
93
|
github: {
|
|
94
94
|
type: "http",
|
|
95
95
|
url: "https://mcp.example.com/mcp",
|
|
96
|
+
connectionTimeout: 10_000,
|
|
96
97
|
},
|
|
97
98
|
}),
|
|
98
99
|
});
|
|
@@ -101,6 +102,10 @@ export default defineToolkit({
|
|
|
101
102
|
Use `AISDKToolkit` in the route. It opens the MCP clients, merges their tools
|
|
102
103
|
with the rest of your toolkit, and closes them when you call `close()`:
|
|
103
104
|
|
|
105
|
+
`connectionTimeout` is optional and measured in milliseconds. Set it to fail
|
|
106
|
+
the server-side MCP readiness flow (`createMCPClient()` plus `tools()`) before
|
|
107
|
+
a bad URL or hanging local process can stall the route.
|
|
108
|
+
|
|
104
109
|
```ts title="app/api/chat/route.ts"
|
|
105
110
|
import { AISDKToolkit } from "@assistant-ui/react-ai-sdk";
|
|
106
111
|
import { openai } from "@ai-sdk/openai";
|
|
@@ -59,20 +59,28 @@ const connectors = [
|
|
|
59
59
|
name: "Weather",
|
|
60
60
|
url: "https://mcp.example.com/weather",
|
|
61
61
|
auth: { type: "none" },
|
|
62
|
+
connectionTimeout: 10_000,
|
|
62
63
|
}),
|
|
63
64
|
];
|
|
64
65
|
|
|
65
66
|
export function Providers({ children }: { children: React.ReactNode }) {
|
|
66
|
-
const aui = useAui({
|
|
67
|
+
const aui = useAui({
|
|
68
|
+
mcp: McpManagerResource({
|
|
69
|
+
connectors,
|
|
70
|
+
connectionTimeout: 15_000,
|
|
71
|
+
}),
|
|
72
|
+
});
|
|
67
73
|
return <AuiProvider value={aui}>{children}</AuiProvider>;
|
|
68
74
|
}
|
|
69
75
|
```
|
|
70
76
|
|
|
71
|
-
Defaults
|
|
77
|
+
Defaults and useful options:
|
|
72
78
|
|
|
73
79
|
- `storage` — `McpLocalStorage()` (override for production; see [Storage](#storage))
|
|
74
80
|
- `oauthRedirectUri` — `${window.location.origin}/mcp/callback`
|
|
75
81
|
- `autoConnect` — `true` (connect on mount when usable auth is persisted)
|
|
82
|
+
- `connectionTimeout` — optional timeout in milliseconds. Set it on the manager as a default or on a connector/custom server to bound the MCP readiness flow (`connect()` plus `listTools()`) with a clear error.
|
|
83
|
+
- Connector `id` values must be unique. The id is used for server lookup, OAuth routing, and model-visible tool names such as `linear__search`.
|
|
76
84
|
|
|
77
85
|
</Step>
|
|
78
86
|
<Step>
|
|
@@ -208,14 +216,20 @@ The callback reads `?state=...&code=...` from the URL, derives the target server
|
|
|
208
216
|
|
|
209
217
|
```tsx
|
|
210
218
|
"use client";
|
|
219
|
+
import { lastAssistantMessageIsCompleteWithToolCalls } from "ai";
|
|
211
220
|
import { useChatRuntime } from "@assistant-ui/react-ai-sdk";
|
|
212
221
|
|
|
213
222
|
export function Chat() {
|
|
214
|
-
const runtime = useChatRuntime({
|
|
223
|
+
const runtime = useChatRuntime({
|
|
224
|
+
api: "/api/chat",
|
|
225
|
+
sendAutomaticallyWhen: lastAssistantMessageIsCompleteWithToolCalls,
|
|
226
|
+
});
|
|
215
227
|
/* … */
|
|
216
228
|
}
|
|
217
229
|
```
|
|
218
230
|
|
|
231
|
+
`sendAutomaticallyWhen` sends completed frontend tool results back to the server so the model can continue after a tool call.
|
|
232
|
+
|
|
219
233
|
Tool names are prefixed `serverId__toolName` to avoid collisions across connected servers. The toolkit re-registers whenever a server connects / disconnects or its tool list changes.
|
|
220
234
|
|
|
221
235
|
If no chat runtime is mounted, `McpManagerResource` brings its own minimal `modelContext` along. Tools are still callable directly:
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Follow-Up Suggestions
|
|
3
|
+
description: Render runtime-generated follow-up prompt chips after an assistant response.
|
|
4
|
+
platforms: ["react"]
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
import { FollowUpSuggestionsSample } from "@/components/docs/samples/follow-up-suggestions";
|
|
8
|
+
|
|
9
|
+
<FollowUpSuggestionsSample />
|
|
10
|
+
|
|
11
|
+
`ThreadFollowupSuggestions` renders the current thread's runtime suggestions as clickable prompt chips. Use it for follow-up prompts that arrive after a response, such as suggested next questions, refinements, or task shortcuts.
|
|
12
|
+
|
|
13
|
+
<Callout type="info">
|
|
14
|
+
This component reads from `thread.suggestions`. For static welcome-screen prompts, use `ThreadPrimitive.Suggestions` instead.
|
|
15
|
+
</Callout>
|
|
16
|
+
|
|
17
|
+
## Getting Started
|
|
18
|
+
|
|
19
|
+
<Steps>
|
|
20
|
+
<Step>
|
|
21
|
+
|
|
22
|
+
### Add `follow-up-suggestions`
|
|
23
|
+
|
|
24
|
+
<InstallCommand shadcn={["follow-up-suggestions"]} />
|
|
25
|
+
|
|
26
|
+
This adds a `/components/assistant-ui/follow-up-suggestions.tsx` file to your project.
|
|
27
|
+
|
|
28
|
+
</Step>
|
|
29
|
+
<Step>
|
|
30
|
+
|
|
31
|
+
### Provide runtime suggestions
|
|
32
|
+
|
|
33
|
+
Pass suggestions through your runtime. External-store runtimes, AI SDK runtimes, and local runtimes can all surface follow-up prompts through `thread.suggestions`.
|
|
34
|
+
|
|
35
|
+
```tsx title="/app/assistant.tsx" {7-10}
|
|
36
|
+
const runtime = useExternalStoreRuntime({
|
|
37
|
+
messages,
|
|
38
|
+
convertMessage,
|
|
39
|
+
onNew: async (message) => {
|
|
40
|
+
// append the message in your store
|
|
41
|
+
},
|
|
42
|
+
suggestions: [
|
|
43
|
+
{ prompt: "Summarize this as action items" },
|
|
44
|
+
{ prompt: "Write a shorter version" },
|
|
45
|
+
],
|
|
46
|
+
});
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
</Step>
|
|
50
|
+
<Step>
|
|
51
|
+
|
|
52
|
+
### Render after messages
|
|
53
|
+
|
|
54
|
+
Place `ThreadFollowupSuggestions` near the bottom of your thread viewport, after the assistant message list and before the composer.
|
|
55
|
+
|
|
56
|
+
```tsx title="/components/assistant-ui/thread.tsx" {1,10}
|
|
57
|
+
import { ThreadFollowupSuggestions } from "@/components/assistant-ui/follow-up-suggestions";
|
|
58
|
+
|
|
59
|
+
const ThreadViewportFooter = () => {
|
|
60
|
+
return (
|
|
61
|
+
<ThreadPrimitive.ViewportFooter>
|
|
62
|
+
<ThreadPrimitive.ScrollToBottom />
|
|
63
|
+
<ThreadFollowupSuggestions />
|
|
64
|
+
<Composer />
|
|
65
|
+
</ThreadPrimitive.ViewportFooter>
|
|
66
|
+
);
|
|
67
|
+
};
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
</Step>
|
|
71
|
+
</Steps>
|
|
72
|
+
|
|
73
|
+
## Behavior
|
|
74
|
+
|
|
75
|
+
The component only renders when the thread is not empty and not currently running. Each suggestion uses `ThreadPrimitive.Suggestion`, replaces the composer text with the prompt, and sends it immediately.
|
|
76
|
+
|
|
77
|
+
## Related Components
|
|
78
|
+
|
|
79
|
+
- [Thread](/docs/ui/thread) - Complete chat interface with message list and composer
|
|
80
|
+
- [Suggestions guide](/docs/guides/suggestions) - Runtime and static suggestion patterns
|
|
@@ -149,7 +149,7 @@ Search is opt-in. Pass `searchable` to the default component:
|
|
|
149
149
|
<ModelSelector models={models} searchable />
|
|
150
150
|
```
|
|
151
151
|
|
|
152
|
-
Or compose `ModelSelector.Search` into a custom layout. Matching runs against each model's `id`, `name`, and `keywords`; add the provider name to `keywords` so typing "openai" finds its models.
|
|
152
|
+
The same prop works on `ModelSelector.Content` when it renders its default children. Or compose `ModelSelector.Search` into a custom layout. Matching runs against each model's `id`, `name`, and `keywords`; add the provider name to `keywords` so typing "openai" finds its models.
|
|
153
153
|
|
|
154
154
|
## Composition
|
|
155
155
|
|
|
@@ -204,6 +204,7 @@ import {
|
|
|
204
204
|
| `ModelSelector.Value` | Selected model name, icon, and active effort |
|
|
205
205
|
| `ModelSelector.Content` | Popover content wrapping a Command |
|
|
206
206
|
| `ModelSelector.Search` | Search input that filters the list |
|
|
207
|
+
| `ModelSelector.FocusAnchor` | Visually hidden input that anchors keyboard navigation when there is no search box |
|
|
207
208
|
| `ModelSelector.List` | List of model items (renders all models by default) |
|
|
208
209
|
| `ModelSelector.Empty` | Empty state shown when search has no matches |
|
|
209
210
|
| `ModelSelector.Group` | Labeled group of items (e.g. by provider) |
|
|
@@ -213,12 +214,20 @@ import {
|
|
|
213
214
|
|
|
214
215
|
`ModelSelector.List` is a Command list, so filtering and keyboard navigation work across groups automatically. Custom sorting is plain code: order the models before rendering items.
|
|
215
216
|
|
|
217
|
+
Keyboard navigation needs a focused input to drive it. When content is unfiltered (`searchable={false}` on `ModelSelector.Content`, or the default children), `ModelSelector.Content` renders a visually hidden `ModelSelector.FocusAnchor` automatically, so custom layouts without a search box stay keyboard-operable. In a custom layout that renders neither `ModelSelector.Search` nor `searchable={false}`, place `ModelSelector.FocusAnchor` yourself to keep the list reachable from the keyboard.
|
|
218
|
+
|
|
216
219
|
<Callout type="warn">
|
|
217
220
|
`ModelSelector.Content` wraps a Command whose root keydown handler claims
|
|
218
|
-
<
|
|
219
|
-
composed inside it (filter chips,
|
|
220
|
-
|
|
221
|
-
|
|
221
|
+
<Kbd>Enter</Kbd> to select the highlighted model and the arrow keys to move
|
|
222
|
+
through the list. Interactive elements composed inside it (filter chips,
|
|
223
|
+
custom effort controls) should stop propagation for the keys they handle in
|
|
224
|
+
their own `onKeyDown` so the focused control responds instead.
|
|
225
|
+
`ModelSelector.Effort` does this for <Kbd>Home</Kbd> / <Kbd>End</Kbd> (which
|
|
226
|
+
cmdk would otherwise use to jump to the first / last model), lets its
|
|
227
|
+
radiogroup own <Kbd>ArrowLeft</Kbd> / <Kbd>ArrowRight</Kbd>, and hands
|
|
228
|
+
<Kbd>ArrowUp</Kbd> / <Kbd>ArrowDown</Kbd> back to the model list by
|
|
229
|
+
refocusing cmdk's input, so the highlight only moves while a following
|
|
230
|
+
<Kbd>Enter</Kbd> can act on it.
|
|
222
231
|
</Callout>
|
|
223
232
|
|
|
224
233
|
## Variants
|
|
@@ -247,6 +256,30 @@ Use the `size` prop to control the trigger dimensions.
|
|
|
247
256
|
<ModelSelector size="lg" /> // Large (h-10)
|
|
248
257
|
```
|
|
249
258
|
|
|
259
|
+
## Keyboard Navigation
|
|
260
|
+
|
|
261
|
+
The picker is fully operable from the keyboard, including when search is disabled.
|
|
262
|
+
|
|
263
|
+
| Key | Action |
|
|
264
|
+
| --- | --- |
|
|
265
|
+
| <Kbd>ArrowDown</Kbd> / <Kbd>ArrowUp</Kbd> | Open the popover from the focused trigger; move between models once open, returning focus to the list from the Thinking row |
|
|
266
|
+
| <Kbd>Enter</Kbd> | Select the highlighted model and close |
|
|
267
|
+
| <Kbd>Escape</Kbd> | Close the popover and return focus to the trigger |
|
|
268
|
+
| <Kbd>Tab</Kbd> | Move from the model list to the Thinking row |
|
|
269
|
+
| <Kbd>ArrowLeft</Kbd> / <Kbd>ArrowRight</Kbd> | Move between reasoning effort levels (Thinking row) |
|
|
270
|
+
| <Kbd>Home</Kbd> / <Kbd>End</Kbd> | Jump to the first / last model (list) or effort level (Thinking row) |
|
|
271
|
+
|
|
272
|
+
When `searchable` is set, typing filters the list; otherwise the keys above drive selection directly.
|
|
273
|
+
|
|
274
|
+
## Accessibility
|
|
275
|
+
|
|
276
|
+
The picker implements the WAI-ARIA combobox pattern over Popover + Command.
|
|
277
|
+
|
|
278
|
+
- The trigger is `role="combobox"` with `aria-haspopup="listbox"`; Radix Popover manages `aria-expanded` and `aria-controls`.
|
|
279
|
+
- The model list is a Command (cmdk) listbox: each item is `role="option"` with `aria-selected`, and the active item is tracked with `aria-activedescendant`.
|
|
280
|
+
- Keyboard navigation works without a visible search box: `ModelSelector.Content` renders a visually hidden input (`ModelSelector.FocusAnchor`) that anchors cmdk's focus so the list stays reachable. Pass `searchable` to surface a real search input instead.
|
|
281
|
+
- The Thinking row (`ModelSelector.Effort`) is a `role="radiogroup"` of `role="radio"` toggles with roving tabindex, so it is a single tab stop and <Kbd>ArrowLeft</Kbd> / <Kbd>ArrowRight</Kbd> move focus and select in one step. <Kbd>ArrowUp</Kbd> / <Kbd>ArrowDown</Kbd> return focus to the model list.
|
|
282
|
+
|
|
250
283
|
## How It Works
|
|
251
284
|
|
|
252
285
|
The default `ModelSelector` export registers the selection with assistant-ui's `ModelContext` system:
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# `@assistant-ui/mcp-docs-server`
|
|
2
2
|
|
|
3
|
-
Model Context Protocol (MCP) server that gives AI assistants direct access to assistant-ui's documentation and example projects. Exposes `assistantUIDocs` (retrieve documentation by path)
|
|
3
|
+
Model Context Protocol (MCP) server that gives AI assistants direct access to assistant-ui's documentation and example projects. Exposes `assistantUIDocs` (retrieve documentation by path), `assistantUIExamples` (access complete example projects), and `assistantUISearch` (keyword search across the bundled docs), and serves the same docs and examples as readable MCP **resources** (`aui-docs:///{path}`, `aui-example:///{name}`).
|
|
4
4
|
|
|
5
5
|
> [!NOTE]
|
|
6
6
|
> Detailed installation, troubleshooting, and advanced usage at [assistant-ui.com/docs/llm#mcp](https://www.assistant-ui.com/docs/llm#mcp).
|
package/dist/constants.d.ts
CHANGED
|
@@ -7,7 +7,8 @@ declare const CODE_EXAMPLES_PATH: string;
|
|
|
7
7
|
declare const MDX_EXTENSION = ".mdx";
|
|
8
8
|
declare const MD_EXTENSION = ".md";
|
|
9
9
|
declare const MAX_FILE_SIZE: number;
|
|
10
|
+
declare const MAX_DIRECTORY_CONTENT_SIZE: number;
|
|
10
11
|
declare const IS_PREPARE_MODE: boolean | undefined;
|
|
11
12
|
//#endregion
|
|
12
|
-
export { CODE_EXAMPLES_PATH, DOCS_PATH, EXAMPLES_PATH, IS_PREPARE_MODE, MAX_FILE_SIZE, MDX_EXTENSION, MD_EXTENSION, PACKAGE_DIR, ROOT_DIR };
|
|
13
|
+
export { CODE_EXAMPLES_PATH, DOCS_PATH, EXAMPLES_PATH, IS_PREPARE_MODE, MAX_DIRECTORY_CONTENT_SIZE, MAX_FILE_SIZE, MDX_EXTENSION, MD_EXTENSION, PACKAGE_DIR, ROOT_DIR };
|
|
13
14
|
//# sourceMappingURL=constants.d.ts.map
|
package/dist/constants.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","names":[],"sources":["../src/constants.ts"],"mappings":";cAKa,QAAA;AAAA,cACA,WAAA;AAAA,cAEA,aAAA;AAAA,cAGA,SAAA;AAAA,cACA,kBAAA;AAAA,cAEA,aAAA;AAAA,cACA,YAAA;AAAA,cAEA,aAAA;AAAA,cAEA,eAAA"}
|
|
1
|
+
{"version":3,"file":"constants.d.ts","names":[],"sources":["../src/constants.ts"],"mappings":";cAKa,QAAA;AAAA,cACA,WAAA;AAAA,cAEA,aAAA;AAAA,cAGA,SAAA;AAAA,cACA,kBAAA;AAAA,cAEA,aAAA;AAAA,cACA,YAAA;AAAA,cAEA,aAAA;AAAA,cAEA,0BAAA;AAAA,cAEA,eAAA"}
|
package/dist/constants.js
CHANGED
|
@@ -11,8 +11,9 @@ const CODE_EXAMPLES_PATH = join(DOCS_BASE, "organized/code-examples");
|
|
|
11
11
|
const MDX_EXTENSION = ".mdx";
|
|
12
12
|
const MD_EXTENSION = ".md";
|
|
13
13
|
const MAX_FILE_SIZE = 10 * 1024 * 1024;
|
|
14
|
+
const MAX_DIRECTORY_CONTENT_SIZE = 1024 * 1024;
|
|
14
15
|
const IS_PREPARE_MODE = process.argv[1]?.includes("prepare-docs/prepare");
|
|
15
16
|
//#endregion
|
|
16
|
-
export { CODE_EXAMPLES_PATH, DOCS_PATH, EXAMPLES_PATH, IS_PREPARE_MODE, MAX_FILE_SIZE, MDX_EXTENSION, MD_EXTENSION, PACKAGE_DIR, ROOT_DIR };
|
|
17
|
+
export { CODE_EXAMPLES_PATH, DOCS_PATH, EXAMPLES_PATH, IS_PREPARE_MODE, MAX_DIRECTORY_CONTENT_SIZE, MAX_FILE_SIZE, MDX_EXTENSION, MD_EXTENSION, PACKAGE_DIR, ROOT_DIR };
|
|
17
18
|
|
|
18
19
|
//# sourceMappingURL=constants.js.map
|
package/dist/constants.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.js","names":[],"sources":["../src/constants.ts"],"sourcesContent":["import { fileURLToPath } from \"node:url\";\nimport { dirname, join } from \"node:path\";\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\nexport const ROOT_DIR = join(__dirname, \"../../../\");\nexport const PACKAGE_DIR = join(__dirname, \"../\");\n\nexport const EXAMPLES_PATH = join(ROOT_DIR, \"examples\");\n\nconst DOCS_BASE = join(PACKAGE_DIR, \".docs\");\nexport const DOCS_PATH = join(DOCS_BASE, \"raw/docs\");\nexport const CODE_EXAMPLES_PATH = join(DOCS_BASE, \"organized/code-examples\");\n\nexport const MDX_EXTENSION = \".mdx\";\nexport const MD_EXTENSION = \".md\";\n\nexport const MAX_FILE_SIZE = 10 * 1024 * 1024;\n\nexport const IS_PREPARE_MODE = process.argv[1]?.includes(\n \"prepare-docs/prepare\",\n);\n"],"mappings":";;;AAGA,MAAM,YAAY,QAAQ,cAAc,OAAO,KAAK,GAAG,CAAC;AAExD,MAAa,WAAW,KAAK,WAAW,WAAW;AACnD,MAAa,cAAc,KAAK,WAAW,KAAK;AAEhD,MAAa,gBAAgB,KAAK,UAAU,UAAU;AAEtD,MAAM,YAAY,KAAK,aAAa,OAAO;AAC3C,MAAa,YAAY,KAAK,WAAW,UAAU;AACnD,MAAa,qBAAqB,KAAK,WAAW,yBAAyB;AAE3E,MAAa,gBAAgB;AAC7B,MAAa,eAAe;AAE5B,MAAa,gBAAgB,KAAK,OAAO;AAEzC,MAAa,kBAAkB,QAAQ,KAAK,EAAE,EAAE,SAC9C,sBACF"}
|
|
1
|
+
{"version":3,"file":"constants.js","names":[],"sources":["../src/constants.ts"],"sourcesContent":["import { fileURLToPath } from \"node:url\";\nimport { dirname, join } from \"node:path\";\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\nexport const ROOT_DIR = join(__dirname, \"../../../\");\nexport const PACKAGE_DIR = join(__dirname, \"../\");\n\nexport const EXAMPLES_PATH = join(ROOT_DIR, \"examples\");\n\nconst DOCS_BASE = join(PACKAGE_DIR, \".docs\");\nexport const DOCS_PATH = join(DOCS_BASE, \"raw/docs\");\nexport const CODE_EXAMPLES_PATH = join(DOCS_BASE, \"organized/code-examples\");\n\nexport const MDX_EXTENSION = \".mdx\";\nexport const MD_EXTENSION = \".md\";\n\nexport const MAX_FILE_SIZE = 10 * 1024 * 1024;\n\nexport const MAX_DIRECTORY_CONTENT_SIZE = 1024 * 1024;\n\nexport const IS_PREPARE_MODE = process.argv[1]?.includes(\n \"prepare-docs/prepare\",\n);\n"],"mappings":";;;AAGA,MAAM,YAAY,QAAQ,cAAc,OAAO,KAAK,GAAG,CAAC;AAExD,MAAa,WAAW,KAAK,WAAW,WAAW;AACnD,MAAa,cAAc,KAAK,WAAW,KAAK;AAEhD,MAAa,gBAAgB,KAAK,UAAU,UAAU;AAEtD,MAAM,YAAY,KAAK,aAAa,OAAO;AAC3C,MAAa,YAAY,KAAK,WAAW,UAAU;AACnD,MAAa,qBAAqB,KAAK,WAAW,yBAAyB;AAE3E,MAAa,gBAAgB;AAC7B,MAAa,eAAe;AAE5B,MAAa,gBAAgB,KAAK,OAAO;AAEzC,MAAa,6BAA6B,OAAO;AAEjD,MAAa,kBAAkB,QAAQ,KAAK,EAAE,EAAE,SAC9C,sBACF"}
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"mappings":";;;cAgBa,MAAA,EAAM,SAGjB;AAAA,iBAmCoB,SAAA,IAAS,OAAA"}
|
package/dist/index.js
CHANGED
|
@@ -2,6 +2,8 @@ import { PACKAGE_DIR } from "./constants.js";
|
|
|
2
2
|
import { logger } from "./utils/logger.js";
|
|
3
3
|
import { docsTools } from "./tools/docs.js";
|
|
4
4
|
import { examplesTools } from "./tools/examples.js";
|
|
5
|
+
import { searchTools } from "./tools/search.js";
|
|
6
|
+
import { registerResources } from "./tools/resources.js";
|
|
5
7
|
import { join } from "node:path";
|
|
6
8
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
7
9
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
@@ -30,6 +32,16 @@ server.registerTool(examplesTools.name, {
|
|
|
30
32
|
openWorldHint: false
|
|
31
33
|
}
|
|
32
34
|
}, examplesTools.execute);
|
|
35
|
+
server.registerTool(searchTools.name, {
|
|
36
|
+
title: "Search assistant-ui Documentation",
|
|
37
|
+
description: searchTools.description,
|
|
38
|
+
inputSchema: searchTools.parameters,
|
|
39
|
+
annotations: {
|
|
40
|
+
readOnlyHint: true,
|
|
41
|
+
openWorldHint: false
|
|
42
|
+
}
|
|
43
|
+
}, searchTools.execute);
|
|
44
|
+
registerResources(server);
|
|
33
45
|
async function runServer() {
|
|
34
46
|
try {
|
|
35
47
|
logger.info(`Starting assistant-ui MCP docs server v${packageJson.version}`);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { docsTools } from \"./tools/docs.js\";\nimport { examplesTools } from \"./tools/examples.js\";\nimport { logger } from \"./utils/logger.js\";\nimport { PACKAGE_DIR } from \"./constants.js\";\n\nimport { readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nconst packageJson = JSON.parse(\n readFileSync(join(PACKAGE_DIR, \"package.json\"), \"utf-8\"),\n);\n\nexport const server = new McpServer({\n name: \"assistant-ui-docs\",\n version: packageJson.version,\n});\n\nserver.registerTool(\n docsTools.name,\n {\n title: \"assistant-ui Documentation\",\n description: docsTools.description,\n inputSchema: docsTools.parameters,\n annotations: { readOnlyHint: true, openWorldHint: false },\n },\n docsTools.execute,\n);\nserver.registerTool(\n examplesTools.name,\n {\n title: \"assistant-ui Examples\",\n description: examplesTools.description,\n inputSchema: examplesTools.parameters,\n annotations: { readOnlyHint: true, openWorldHint: false },\n },\n examplesTools.execute,\n);\n\nexport async function runServer() {\n try {\n logger.info(\n `Starting assistant-ui MCP docs server v${packageJson.version}`,\n );\n const transport = new StdioServerTransport();\n await server.connect(transport);\n } catch (error) {\n logger.error(\"Failed to start MCP server\", error);\n process.exit(1);\n }\n}\n\nif (import.meta.url === `file://${process.argv[1]}`) {\n void runServer().catch((error) => {\n console.error(\"Failed to start server:\", error);\n process.exit(1);\n });\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { docsTools } from \"./tools/docs.js\";\nimport { examplesTools } from \"./tools/examples.js\";\nimport { searchTools } from \"./tools/search.js\";\nimport { registerResources } from \"./tools/resources.js\";\nimport { logger } from \"./utils/logger.js\";\nimport { PACKAGE_DIR } from \"./constants.js\";\n\nimport { readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nconst packageJson = JSON.parse(\n readFileSync(join(PACKAGE_DIR, \"package.json\"), \"utf-8\"),\n);\n\nexport const server = new McpServer({\n name: \"assistant-ui-docs\",\n version: packageJson.version,\n});\n\nserver.registerTool(\n docsTools.name,\n {\n title: \"assistant-ui Documentation\",\n description: docsTools.description,\n inputSchema: docsTools.parameters,\n annotations: { readOnlyHint: true, openWorldHint: false },\n },\n docsTools.execute,\n);\nserver.registerTool(\n examplesTools.name,\n {\n title: \"assistant-ui Examples\",\n description: examplesTools.description,\n inputSchema: examplesTools.parameters,\n annotations: { readOnlyHint: true, openWorldHint: false },\n },\n examplesTools.execute,\n);\nserver.registerTool(\n searchTools.name,\n {\n title: \"Search assistant-ui Documentation\",\n description: searchTools.description,\n inputSchema: searchTools.parameters,\n annotations: { readOnlyHint: true, openWorldHint: false },\n },\n searchTools.execute,\n);\n\nregisterResources(server);\n\nexport async function runServer() {\n try {\n logger.info(\n `Starting assistant-ui MCP docs server v${packageJson.version}`,\n );\n const transport = new StdioServerTransport();\n await server.connect(transport);\n } catch (error) {\n logger.error(\"Failed to start MCP server\", error);\n process.exit(1);\n }\n}\n\nif (import.meta.url === `file://${process.argv[1]}`) {\n void runServer().catch((error) => {\n console.error(\"Failed to start server:\", error);\n process.exit(1);\n });\n}\n"],"mappings":";;;;;;;;;;;AAYA,MAAM,cAAc,KAAK,MACvB,aAAa,KAAK,aAAa,cAAc,GAAG,OAAO,CACzD;AAEA,MAAa,SAAS,IAAI,UAAU;CAClC,MAAM;CACN,SAAS,YAAY;AACvB,CAAC;AAED,OAAO,aACL,UAAU,MACV;CACE,OAAO;CACP,aAAa,UAAU;CACvB,aAAa,UAAU;CACvB,aAAa;EAAE,cAAc;EAAM,eAAe;CAAM;AAC1D,GACA,UAAU,OACZ;AACA,OAAO,aACL,cAAc,MACd;CACE,OAAO;CACP,aAAa,cAAc;CAC3B,aAAa,cAAc;CAC3B,aAAa;EAAE,cAAc;EAAM,eAAe;CAAM;AAC1D,GACA,cAAc,OAChB;AACA,OAAO,aACL,YAAY,MACZ;CACE,OAAO;CACP,aAAa,YAAY;CACzB,aAAa,YAAY;CACzB,aAAa;EAAE,cAAc;EAAM,eAAe;CAAM;AAC1D,GACA,YAAY,OACd;AAEA,kBAAkB,MAAM;AAExB,eAAsB,YAAY;CAChC,IAAI;EACF,OAAO,KACL,0CAA0C,YAAY,SACxD;EACA,MAAM,YAAY,IAAI,qBAAqB;EAC3C,MAAM,OAAO,QAAQ,SAAS;CAChC,SAAS,OAAO;EACd,OAAO,MAAM,8BAA8B,KAAK;EAChD,QAAQ,KAAK,CAAC;CAChB;AACF;AAEA,IAAI,OAAO,KAAK,QAAQ,UAAU,QAAQ,KAAK,MAC7C,UAAe,CAAC,CAAC,OAAO,UAAU;CAChC,QAAQ,MAAM,2BAA2B,KAAK;CAC9C,QAAQ,KAAK,CAAC;AAChB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"copy-raw.d.ts","names":[],"sources":["../../src/prepare-docs/copy-raw.ts"],"mappings":";
|
|
1
|
+
{"version":3,"file":"copy-raw.d.ts","names":[],"sources":["../../src/prepare-docs/copy-raw.ts"],"mappings":";iBAiCsB,OAAA,IAAW,OAAO"}
|
|
@@ -4,7 +4,6 @@ import { extname, join } from "node:path";
|
|
|
4
4
|
import { copyFile, mkdir, readdir, rm } from "node:fs/promises";
|
|
5
5
|
//#region src/prepare-docs/copy-raw.ts
|
|
6
6
|
const DOCS_SOURCE = join(ROOT_DIR, "apps/docs/content/docs");
|
|
7
|
-
const BLOG_SOURCE = join(ROOT_DIR, "apps/docs/content/blog");
|
|
8
7
|
const DOCS_DEST = join(ROOT_DIR, "packages/mcp-docs-server/.docs/raw");
|
|
9
8
|
async function copyDir(src, dest) {
|
|
10
9
|
try {
|
|
@@ -38,9 +37,6 @@ async function copyRaw() {
|
|
|
38
37
|
const docsPath = join(DOCS_DEST, "docs");
|
|
39
38
|
await copyDir(DOCS_SOURCE, docsPath);
|
|
40
39
|
logger.info(`Copied documentation to ${docsPath}`);
|
|
41
|
-
const blogPath = join(DOCS_DEST, "blog");
|
|
42
|
-
await copyDir(BLOG_SOURCE, blogPath);
|
|
43
|
-
logger.info(`Copied blog posts to ${blogPath}`);
|
|
44
40
|
logger.info("Raw documentation copy complete");
|
|
45
41
|
} catch (error) {
|
|
46
42
|
logger.error("Failed to copy raw documentation", error);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"copy-raw.js","names":[],"sources":["../../src/prepare-docs/copy-raw.ts"],"sourcesContent":["import { rm, mkdir, readdir, copyFile } from \"node:fs/promises\";\nimport { join, extname } from \"node:path\";\nimport { logger } from \"../utils/logger.js\";\nimport { ROOT_DIR } from \"../constants.js\";\n\nconst DOCS_SOURCE = join(ROOT_DIR, \"apps/docs/content/docs\");\nconst
|
|
1
|
+
{"version":3,"file":"copy-raw.js","names":[],"sources":["../../src/prepare-docs/copy-raw.ts"],"sourcesContent":["import { rm, mkdir, readdir, copyFile } from \"node:fs/promises\";\nimport { join, extname } from \"node:path\";\nimport { logger } from \"../utils/logger.js\";\nimport { ROOT_DIR } from \"../constants.js\";\n\nconst DOCS_SOURCE = join(ROOT_DIR, \"apps/docs/content/docs\");\nconst DOCS_DEST = join(ROOT_DIR, \"packages/mcp-docs-server/.docs/raw\");\n\nasync function copyDir(src: string, dest: string): Promise<void> {\n try {\n await mkdir(dest, { recursive: true });\n const entries = await readdir(src, { withFileTypes: true });\n\n for (const entry of entries) {\n const srcPath = join(src, entry.name);\n const destPath = join(dest, entry.name);\n\n if (entry.isDirectory()) {\n await copyDir(srcPath, destPath);\n } else if (entry.isFile()) {\n const ext = extname(entry.name).toLowerCase();\n if (ext === \".mdx\" || ext === \".md\") {\n await copyFile(srcPath, destPath);\n logger.debug(`Copied: ${srcPath} -> ${destPath}`);\n }\n }\n }\n } catch (error) {\n logger.error(`Failed to copy directory: ${src}`, error);\n throw error;\n }\n}\n\nexport async function copyRaw(): Promise<void> {\n logger.info(\"Copying raw documentation files...\");\n\n try {\n await rm(DOCS_DEST, { recursive: true, force: true });\n await mkdir(DOCS_DEST, { recursive: true });\n\n const docsPath = join(DOCS_DEST, \"docs\");\n await copyDir(DOCS_SOURCE, docsPath);\n logger.info(`Copied documentation to ${docsPath}`);\n\n logger.info(\"Raw documentation copy complete\");\n } catch (error) {\n logger.error(\"Failed to copy raw documentation\", error);\n throw error;\n }\n}\n"],"mappings":";;;;;AAKA,MAAM,cAAc,KAAK,UAAU,wBAAwB;AAC3D,MAAM,YAAY,KAAK,UAAU,oCAAoC;AAErE,eAAe,QAAQ,KAAa,MAA6B;CAC/D,IAAI;EACF,MAAM,MAAM,MAAM,EAAE,WAAW,KAAK,CAAC;EACrC,MAAM,UAAU,MAAM,QAAQ,KAAK,EAAE,eAAe,KAAK,CAAC;EAE1D,KAAK,MAAM,SAAS,SAAS;GAC3B,MAAM,UAAU,KAAK,KAAK,MAAM,IAAI;GACpC,MAAM,WAAW,KAAK,MAAM,MAAM,IAAI;GAEtC,IAAI,MAAM,YAAY,GACpB,MAAM,QAAQ,SAAS,QAAQ;QAC1B,IAAI,MAAM,OAAO,GAAG;IACzB,MAAM,MAAM,QAAQ,MAAM,IAAI,CAAC,CAAC,YAAY;IAC5C,IAAI,QAAQ,UAAU,QAAQ,OAAO;KACnC,MAAM,SAAS,SAAS,QAAQ;KAChC,OAAO,MAAM,WAAW,QAAQ,MAAM,UAAU;IAClD;GACF;EACF;CACF,SAAS,OAAO;EACd,OAAO,MAAM,6BAA6B,OAAO,KAAK;EACtD,MAAM;CACR;AACF;AAEA,eAAsB,UAAyB;CAC7C,OAAO,KAAK,oCAAoC;CAEhD,IAAI;EACF,MAAM,GAAG,WAAW;GAAE,WAAW;GAAM,OAAO;EAAK,CAAC;EACpD,MAAM,MAAM,WAAW,EAAE,WAAW,KAAK,CAAC;EAE1C,MAAM,WAAW,KAAK,WAAW,MAAM;EACvC,MAAM,QAAQ,aAAa,QAAQ;EACnC,OAAO,KAAK,2BAA2B,UAAU;EAEjD,OAAO,KAAK,iCAAiC;CAC/C,SAAS,OAAO;EACd,OAAO,MAAM,oCAAoC,KAAK;EACtD,MAAM;CACR;AACF"}
|
package/dist/tools/docs.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"docs.d.ts","names":[],"sources":["../../src/tools/docs.ts"],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"docs.d.ts","names":[],"sources":["../../src/tools/docs.ts"],"mappings":";;;cAoBM,eAAA,EAAe,CAAA,CAAA,SAAA;;;;;;;cAyKR,SAAA;;;;;;;;KAKgB,CAAA,CAAE,KAAA,QAAa,eAAA,MAAgB,OAAA"}
|