@assistant-ui/mcp-docs-server 0.1.36 → 0.1.39
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 +8 -9
- package/.docs/organized/code-examples/with-a2a.md +16 -11
- package/.docs/organized/code-examples/with-ag-ui.md +16 -11
- package/.docs/organized/code-examples/{with-ai-sdk-v6.md → with-ai-sdk-v7.md} +32 -21
- package/.docs/organized/code-examples/with-artifacts.md +17 -10
- package/.docs/organized/code-examples/with-assistant-transport.md +15 -8
- package/.docs/organized/code-examples/with-browser-extension.md +15 -8
- package/.docs/organized/code-examples/with-chain-of-thought.md +17 -10
- package/.docs/organized/code-examples/with-cloud-standalone.md +10 -9
- package/.docs/organized/code-examples/with-cloud.md +18 -13
- package/.docs/organized/code-examples/with-custom-thread-list.md +17 -10
- package/.docs/organized/code-examples/with-elevenlabs-conversational.md +20 -13
- package/.docs/organized/code-examples/with-elevenlabs-scribe.md +20 -13
- package/.docs/organized/code-examples/with-eve.md +16 -9
- package/.docs/organized/code-examples/with-expo.md +26 -23
- package/.docs/organized/code-examples/with-external-store.md +16 -11
- package/.docs/organized/code-examples/with-ffmpeg.md +18 -13
- package/.docs/organized/code-examples/with-generative-ui.md +20 -15
- package/.docs/organized/code-examples/with-google-adk.md +16 -9
- package/.docs/organized/code-examples/with-heat-graph.md +8 -9
- package/.docs/organized/code-examples/with-image-generation.md +17 -10
- package/.docs/organized/code-examples/with-interactables.md +19 -15
- package/.docs/organized/code-examples/with-langchain.md +17 -10
- package/.docs/organized/code-examples/with-langgraph.md +17 -10
- package/.docs/organized/code-examples/with-livekit.md +21 -14
- package/.docs/organized/code-examples/with-mcp.md +40 -18
- package/.docs/organized/code-examples/with-opencode.md +22 -17
- package/.docs/organized/code-examples/with-pi.md +47 -12
- package/.docs/organized/code-examples/with-react-hook-form.md +19 -14
- package/.docs/organized/code-examples/with-react-ink-web.md +6 -6
- package/.docs/organized/code-examples/with-react-ink.md +2 -2
- package/.docs/organized/code-examples/with-react-router.md +20 -15
- package/.docs/organized/code-examples/with-resumable-stream.md +19 -12
- package/.docs/organized/code-examples/with-store.md +8 -9
- package/.docs/organized/code-examples/with-tanstack.md +17 -11
- package/.docs/organized/code-examples/with-tap-runtime.md +16 -11
- package/.docs/organized/code-examples/with-virtualized-thread.md +17 -12
- package/.docs/raw/docs/(docs)/base-ui.mdx +39 -0
- package/.docs/raw/docs/(docs)/cli.mdx +18 -2
- package/.docs/raw/docs/(docs)/installation.mdx +15 -1
- package/.docs/raw/docs/(docs)/rtl.mdx +2 -4
- package/.docs/raw/docs/(reference)/api-reference/generative-ui/actions.mdx +56 -0
- package/.docs/raw/docs/(reference)/api-reference/generative-ui/components.mdx +86 -0
- package/.docs/raw/docs/(reference)/api-reference/generative-ui/index.mdx +19 -1
- package/.docs/raw/docs/(reference)/api-reference/generative-ui/json-generative-ui.mdx +42 -0
- package/.docs/raw/docs/(reference)/api-reference/generative-ui/rendering.mdx +53 -2
- package/.docs/raw/docs/(reference)/api-reference/generative-ui/slack.mdx +81 -0
- package/.docs/raw/docs/(reference)/api-reference/generative-ui/teams.mdx +86 -0
- package/.docs/raw/docs/(reference)/api-reference/generative-ui/tokens.mdx +62 -0
- package/.docs/raw/docs/(reference)/api-reference/integrations/index.mdx +4 -1
- package/.docs/raw/docs/(reference)/api-reference/integrations/react-ai-sdk.mdx +4 -2
- package/.docs/raw/docs/(reference)/api-reference/integrations/react-data-stream.mdx +37 -0
- package/.docs/raw/docs/(reference)/api-reference/overview.mdx +1 -0
- package/.docs/raw/docs/(reference)/api-reference/primitives/assistant-if.mdx +29 -29
- package/.docs/raw/docs/(reference)/api-reference/primitives/composition.mdx +1 -0
- package/.docs/raw/docs/(reference)/api-reference/primitives/index.mdx +3 -0
- package/.docs/raw/docs/(reference)/api-reference/primitives/selection-toolbar.mdx +2 -0
- package/.docs/raw/docs/(reference)/api-reference/tools/status.mdx +0 -2
- package/.docs/raw/docs/(reference)/api-reference/tools/toolkits.mdx +12 -9
- package/.docs/raw/docs/(reference)/api-reference/utilities/miscellaneous.mdx +4 -0
- package/.docs/raw/docs/cloud/ai-sdk-assistant-ui.mdx +7 -1
- package/.docs/raw/docs/cloud/langgraph.mdx +4 -2
- package/.docs/raw/docs/guides/chatgpt-subscription.mdx +108 -0
- package/.docs/raw/docs/guides/dictation.mdx +185 -257
- package/.docs/raw/docs/guides/index.mdx +10 -0
- package/.docs/raw/docs/guides/mentions.mdx +31 -3
- package/.docs/raw/docs/guides/resumable-streams.mdx +12 -1
- package/.docs/raw/docs/guides/speech.mdx +47 -29
- package/.docs/raw/docs/guides/suggestions.mdx +70 -1
- package/.docs/raw/docs/guides/voice.mdx +197 -267
- package/.docs/raw/docs/ink/primitives.mdx +35 -1
- package/.docs/raw/docs/integrations/frameworks/ai-sdk.mdx +13 -7
- package/.docs/raw/docs/integrations/frameworks/cloudflare-agents/overview.mdx +3 -3
- package/.docs/raw/docs/integrations/frameworks/mastra/full-stack.mdx +1 -1
- package/.docs/raw/docs/integrations/frameworks/mastra/overview.mdx +3 -3
- 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/index.mdx +1 -1
- package/.docs/raw/docs/integrations/observability/helicone.mdx +1 -1
- package/.docs/raw/docs/integrations/observability/langfuse.mdx +1 -1
- package/.docs/raw/docs/integrations/observability/langsmith.mdx +3 -3
- package/.docs/raw/docs/migrations/index.mdx +50 -0
- package/.docs/raw/docs/migrations/react-langgraph-v0-7.mdx +2 -2
- package/.docs/raw/docs/migrations/toolkit-tools.mdx +4 -2
- package/.docs/raw/docs/primitives/chain-of-thought.mdx +6 -1
- package/.docs/raw/docs/primitives/composer.mdx +16 -0
- package/.docs/raw/docs/primitives/selection-toolbar.mdx +25 -0
- package/.docs/raw/docs/primitives/thread-list.mdx +30 -6
- package/.docs/raw/docs/react-native/primitives.mdx +23 -0
- package/.docs/raw/docs/runtimes/a2a/quickstart.mdx +1 -1
- package/.docs/raw/docs/runtimes/ag-ui/agent-state.mdx +124 -0
- package/.docs/raw/docs/runtimes/ag-ui/quickstart.mdx +1 -1
- package/.docs/raw/docs/runtimes/ag-ui/runtime-options.mdx +13 -2
- package/.docs/raw/docs/runtimes/ai-sdk/overview.mdx +13 -4
- package/.docs/raw/docs/runtimes/ai-sdk/v4-legacy.mdx +11 -11
- package/.docs/raw/docs/runtimes/ai-sdk/v5-legacy.mdx +5 -5
- package/.docs/raw/docs/runtimes/ai-sdk/{v6.mdx → v6-legacy.mdx} +8 -6
- package/.docs/raw/docs/runtimes/ai-sdk/v7.mdx +717 -0
- package/.docs/raw/docs/runtimes/concepts/adapters.mdx +1 -1
- package/.docs/raw/docs/runtimes/concepts/architecture.mdx +1 -1
- package/.docs/raw/docs/runtimes/custom/data-stream.mdx +10 -19
- package/.docs/raw/docs/runtimes/custom/external-store.mdx +1 -1
- package/.docs/raw/docs/runtimes/custom/local-runtime.mdx +2 -0
- package/.docs/raw/docs/runtimes/eve/overview.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/langgraph/agent-state.mdx +181 -0
- package/.docs/raw/docs/runtimes/opencode/hooks.mdx +1 -1
- package/.docs/raw/docs/tools/backend.mdx +6 -3
- package/.docs/raw/docs/tools/defining-tools.mdx +12 -1
- package/.docs/raw/docs/tools/generative-ui.mdx +95 -0
- package/.docs/raw/docs/tools/mcp-apps.mdx +37 -10
- package/.docs/raw/docs/tools/mcp.mdx +105 -3
- package/.docs/raw/docs/tools/tool-ui.mdx +6 -4
- package/.docs/raw/docs/tools/user-managed-mcp.mdx +41 -4
- package/.docs/raw/docs/ui/accordion.mdx +16 -10
- package/.docs/raw/docs/ui/assistant-modal.mdx +8 -4
- package/.docs/raw/docs/ui/attachment.mdx +5 -1
- package/.docs/raw/docs/ui/badge.mdx +23 -12
- package/.docs/raw/docs/ui/follow-up-suggestions.mdx +80 -0
- package/.docs/raw/docs/ui/model-selector.mdx +69 -6
- package/.docs/raw/docs/ui/select.mdx +22 -14
- package/.docs/raw/docs/ui/sources.mdx +1 -1
- package/.docs/raw/docs/ui/tabs.mdx +25 -14
- package/.docs/raw/docs/utilities/heat-graph.mdx +2 -2
- 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 +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +51 -0
- package/dist/index.js.map +1 -1
- package/dist/prepare-docs/code-examples.d.ts.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/prompts/xulux-playground.d.ts +12 -0
- package/dist/prompts/xulux-playground.d.ts.map +1 -0
- package/dist/prompts/xulux-playground.js +33 -0
- package/dist/prompts/xulux-playground.js.map +1 -0
- package/dist/tools/docs.d.ts +2 -4
- package/dist/tools/docs.d.ts.map +1 -1
- package/dist/tools/docs.js +38 -10
- package/dist/tools/docs.js.map +1 -1
- package/dist/tools/examples.d.ts +5 -5
- package/dist/tools/examples.d.ts.map +1 -1
- package/dist/tools/examples.js +10 -7
- package/dist/tools/examples.js.map +1 -1
- package/dist/tools/resources.d.ts +6 -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 +30 -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 +7 -1
- package/dist/tools/tests/test-setup.js.map +1 -1
- package/dist/tools/xulux-templates.d.ts +72 -0
- package/dist/tools/xulux-templates.d.ts.map +1 -0
- package/dist/tools/xulux-templates.js +82 -0
- package/dist/tools/xulux-templates.js.map +1 -0
- package/dist/utils/cache.d.ts +5 -0
- package/dist/utils/cache.d.ts.map +1 -0
- package/dist/utils/cache.js +18 -0
- package/dist/utils/cache.js.map +1 -0
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/mcp-format.d.ts +1 -0
- package/dist/utils/mcp-format.d.ts.map +1 -1
- package/dist/utils/mcp-format.js +7 -4
- package/dist/utils/mcp-format.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 +20 -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/dist/utils/security.d.ts.map +1 -1
- package/dist/xulux/catalog-client.d.ts +14 -0
- package/dist/xulux/catalog-client.d.ts.map +1 -0
- package/dist/xulux/catalog-client.js +67 -0
- package/dist/xulux/catalog-client.js.map +1 -0
- package/dist/xulux/fallback-catalog.d.ts +7 -0
- package/dist/xulux/fallback-catalog.d.ts.map +1 -0
- package/dist/xulux/fallback-catalog.js +47 -0
- package/dist/xulux/fallback-catalog.js.map +1 -0
- package/dist/xulux/fetch-sandbox.d.ts +5 -0
- package/dist/xulux/fetch-sandbox.d.ts.map +1 -0
- package/dist/xulux/fetch-sandbox.js +40 -0
- package/dist/xulux/fetch-sandbox.js.map +1 -0
- package/dist/xulux/template-service.d.ts +84 -0
- package/dist/xulux/template-service.d.ts.map +1 -0
- package/dist/xulux/template-service.js +223 -0
- package/dist/xulux/template-service.js.map +1 -0
- package/dist/xulux/types.d.ts +55 -0
- package/dist/xulux/types.d.ts.map +1 -0
- package/dist/xulux/types.js +6 -0
- package/dist/xulux/types.js.map +1 -0
- package/package.json +5 -5
- package/src/constants.ts +2 -0
- package/src/index.ts +67 -0
- package/src/prepare-docs/copy-raw.ts +0 -5
- package/src/prompts/xulux-playground.ts +36 -0
- package/src/tools/docs.ts +52 -4
- package/src/tools/examples.ts +18 -11
- 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/docs.test.ts +20 -0
- package/src/tools/tests/examples.test.ts +5 -5
- package/src/tools/tests/listings-cache.test.ts +19 -0
- package/src/tools/tests/mcp-protocol.test.ts +92 -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 +10 -0
- package/src/tools/tests/xulux-templates.test.ts +262 -0
- package/src/tools/xulux-templates.ts +141 -0
- package/src/utils/cache.ts +20 -0
- package/src/utils/mcp-format.ts +8 -6
- package/src/utils/mdx.ts +21 -1
- package/src/utils/paths.ts +25 -0
- package/src/utils/search.ts +131 -0
- package/src/utils/tests/cache.test.ts +51 -0
- package/src/utils/tests/mcp-format.test.ts +22 -0
- package/src/utils/tests/security.test.ts +1 -1
- package/src/xulux/catalog-client.ts +105 -0
- package/src/xulux/fallback-catalog.ts +63 -0
- package/src/xulux/fetch-sandbox.ts +56 -0
- package/src/xulux/template-service.ts +406 -0
- package/src/xulux/types.ts +60 -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
- package/.docs/raw/docs/(reference)/api-reference/hooks/utilities.mdx +0 -464
package/src/tools/docs.ts
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import { z } from "zod/v3";
|
|
2
2
|
import { stat, lstat } from "node:fs/promises";
|
|
3
3
|
import { join, extname } from "node:path";
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
DOCS_PATH,
|
|
6
|
+
MDX_EXTENSION,
|
|
7
|
+
MAX_FILE_SIZE,
|
|
8
|
+
MAX_DIRECTORY_CONTENT_SIZE,
|
|
9
|
+
} from "../constants.js";
|
|
5
10
|
import { logger } from "../utils/logger.js";
|
|
6
11
|
import {
|
|
7
12
|
listDirContents,
|
|
@@ -29,7 +34,11 @@ interface DocResult {
|
|
|
29
34
|
content?: string;
|
|
30
35
|
files?: string[];
|
|
31
36
|
directories?: string[];
|
|
37
|
+
summaries?: Array<{ name: string; title?: string; excerpt?: string }>;
|
|
38
|
+
title?: string;
|
|
39
|
+
excerpt?: string;
|
|
32
40
|
suggestions?: string[];
|
|
41
|
+
hint?: string;
|
|
33
42
|
error?: string;
|
|
34
43
|
}
|
|
35
44
|
|
|
@@ -79,16 +88,46 @@ async function readDocumentation(docPath: string): Promise<DocResult> {
|
|
|
79
88
|
const { directories, files } = await listDirContents(fullPath);
|
|
80
89
|
|
|
81
90
|
const contents: Record<string, string> = {};
|
|
91
|
+
const summaries: Array<{
|
|
92
|
+
name: string;
|
|
93
|
+
title?: string;
|
|
94
|
+
excerpt?: string;
|
|
95
|
+
}> = [];
|
|
96
|
+
let aggregateSize = 0;
|
|
97
|
+
let truncated = false;
|
|
82
98
|
for (const file of files) {
|
|
99
|
+
let fileSize: number;
|
|
100
|
+
try {
|
|
101
|
+
fileSize = (await stat(join(fullPath, file))).size;
|
|
102
|
+
} catch (error) {
|
|
103
|
+
logger.warn(
|
|
104
|
+
`Failed to stat MDX file: ${join(fullPath, file)}`,
|
|
105
|
+
error,
|
|
106
|
+
);
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
aggregateSize += fileSize;
|
|
110
|
+
if (aggregateSize > MAX_DIRECTORY_CONTENT_SIZE) {
|
|
111
|
+
truncated = true;
|
|
112
|
+
break;
|
|
113
|
+
}
|
|
83
114
|
const mdxContent = await readMDXFile(join(fullPath, file));
|
|
84
115
|
if (mdxContent) {
|
|
85
|
-
const
|
|
86
|
-
contents[
|
|
116
|
+
const name = file.replace(MDX_EXTENSION, "");
|
|
117
|
+
contents[name] = formatMDXContent(mdxContent);
|
|
118
|
+
const title = mdxContent.frontmatter["title"];
|
|
119
|
+
summaries.push({
|
|
120
|
+
name,
|
|
121
|
+
...(typeof title === "string" && { title }),
|
|
122
|
+
...(mdxContent.excerpt !== undefined && {
|
|
123
|
+
excerpt: mdxContent.excerpt,
|
|
124
|
+
}),
|
|
125
|
+
});
|
|
87
126
|
}
|
|
88
127
|
}
|
|
89
128
|
|
|
90
129
|
const content =
|
|
91
|
-
Object.keys(contents).length > 0
|
|
130
|
+
!truncated && Object.keys(contents).length > 0
|
|
92
131
|
? JSON.stringify(contents, null, 2)
|
|
93
132
|
: undefined;
|
|
94
133
|
return {
|
|
@@ -97,7 +136,11 @@ async function readDocumentation(docPath: string): Promise<DocResult> {
|
|
|
97
136
|
type: "directory",
|
|
98
137
|
directories,
|
|
99
138
|
files: files.map((f) => f.replace(MDX_EXTENSION, "")),
|
|
139
|
+
...(summaries.length > 0 && { summaries }),
|
|
100
140
|
...(content !== undefined && { content }),
|
|
141
|
+
...(truncated && {
|
|
142
|
+
hint: `Directory content exceeds ${MAX_DIRECTORY_CONTENT_SIZE} bytes and was omitted; summaries cover only the files read before the limit. Request individual files by path to retrieve their content.`,
|
|
143
|
+
}),
|
|
101
144
|
};
|
|
102
145
|
}
|
|
103
146
|
}
|
|
@@ -132,11 +175,16 @@ async function readDocumentation(docPath: string): Promise<DocResult> {
|
|
|
132
175
|
const mdxContent = await readMDXFile(mdxPath);
|
|
133
176
|
|
|
134
177
|
if (mdxContent) {
|
|
178
|
+
const title = mdxContent.frontmatter["title"];
|
|
135
179
|
return {
|
|
136
180
|
path: docPath,
|
|
137
181
|
found: true,
|
|
138
182
|
type: "file",
|
|
139
183
|
content: formatMDXContent(mdxContent),
|
|
184
|
+
...(typeof title === "string" && { title }),
|
|
185
|
+
...(mdxContent.excerpt !== undefined && {
|
|
186
|
+
excerpt: mdxContent.excerpt,
|
|
187
|
+
}),
|
|
140
188
|
};
|
|
141
189
|
}
|
|
142
190
|
}
|
package/src/tools/examples.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { z } from "zod/v3";
|
|
|
2
2
|
import { readFile, readdir, lstat } from "node:fs/promises";
|
|
3
3
|
import { join, extname } from "node:path";
|
|
4
4
|
import { CODE_EXAMPLES_PATH, MAX_FILE_SIZE } from "../constants.js";
|
|
5
|
+
import { cacheListing } from "../utils/cache.js";
|
|
5
6
|
import { logger } from "../utils/logger.js";
|
|
6
7
|
import { formatMCPResponse } from "../utils/mcp-format.js";
|
|
7
8
|
import { sanitizePath } from "../utils/security.js";
|
|
@@ -11,24 +12,30 @@ const examplesInputSchema = z.object({
|
|
|
11
12
|
.string()
|
|
12
13
|
.optional()
|
|
13
14
|
.describe(
|
|
14
|
-
'Example name (e.g., "with-ai-sdk-
|
|
15
|
+
'Example name (e.g., "with-ai-sdk-v7"). Leave empty to list all examples.',
|
|
15
16
|
),
|
|
16
17
|
});
|
|
17
18
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
.filter((file) => extname(file) === ".md")
|
|
23
|
-
.map((file) => file.replace(".md", ""))
|
|
24
|
-
.sort();
|
|
25
|
-
} catch (error) {
|
|
19
|
+
const loadCodeExamples = cacheListing(scanCodeExamples);
|
|
20
|
+
|
|
21
|
+
export function listCodeExamples(): Promise<string[]> {
|
|
22
|
+
return loadCodeExamples().catch((error) => {
|
|
26
23
|
logger.error("Failed to list code examples", error);
|
|
27
24
|
return [];
|
|
28
|
-
}
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async function scanCodeExamples(): Promise<string[]> {
|
|
29
|
+
const files = await readdir(CODE_EXAMPLES_PATH);
|
|
30
|
+
return files
|
|
31
|
+
.filter((file) => extname(file) === ".md")
|
|
32
|
+
.map((file) => file.replace(".md", ""))
|
|
33
|
+
.sort();
|
|
29
34
|
}
|
|
30
35
|
|
|
31
|
-
async function readCodeExample(
|
|
36
|
+
export async function readCodeExample(
|
|
37
|
+
exampleName: string,
|
|
38
|
+
): Promise<string | null> {
|
|
32
39
|
try {
|
|
33
40
|
const sanitized = sanitizePath(exampleName);
|
|
34
41
|
const filePath = join(CODE_EXAMPLES_PATH, `${sanitized}.md`);
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import {
|
|
2
|
+
McpServer,
|
|
3
|
+
ResourceTemplate,
|
|
4
|
+
} from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
import { DOCS_PATH, MDX_EXTENSION } from "../constants.js";
|
|
7
|
+
import { getAvailableDocFiles } from "../utils/paths.js";
|
|
8
|
+
import { readMDXFileSafe, formatMDXContent } from "../utils/mdx.js";
|
|
9
|
+
import { sanitizePath } from "../utils/security.js";
|
|
10
|
+
import { listCodeExamples, readCodeExample } from "./examples.js";
|
|
11
|
+
import { logger } from "../utils/logger.js";
|
|
12
|
+
|
|
13
|
+
const MARKDOWN_MIME_TYPE = "text/markdown";
|
|
14
|
+
const DOCS_SCHEME = "aui-docs";
|
|
15
|
+
const EXAMPLE_SCHEME = "aui-example";
|
|
16
|
+
|
|
17
|
+
function templateVarToPath(value: string | string[] | undefined): string {
|
|
18
|
+
if (Array.isArray(value)) return value.join("/");
|
|
19
|
+
return value ?? "";
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
interface MarkdownResourceConfig {
|
|
23
|
+
name: string;
|
|
24
|
+
scheme: string;
|
|
25
|
+
variable: string;
|
|
26
|
+
title: string;
|
|
27
|
+
description: string;
|
|
28
|
+
notFoundLabel: string;
|
|
29
|
+
list: () => Promise<string[]>;
|
|
30
|
+
read: (key: string) => Promise<string | null>;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function registerMarkdownResource(
|
|
34
|
+
server: McpServer,
|
|
35
|
+
config: MarkdownResourceConfig,
|
|
36
|
+
): void {
|
|
37
|
+
const {
|
|
38
|
+
name,
|
|
39
|
+
scheme,
|
|
40
|
+
variable,
|
|
41
|
+
title,
|
|
42
|
+
description,
|
|
43
|
+
notFoundLabel,
|
|
44
|
+
list,
|
|
45
|
+
read,
|
|
46
|
+
} = config;
|
|
47
|
+
server.registerResource(
|
|
48
|
+
name,
|
|
49
|
+
new ResourceTemplate(`${scheme}:///{+${variable}}`, {
|
|
50
|
+
list: async () => ({
|
|
51
|
+
resources: (await list()).map((key) => ({
|
|
52
|
+
uri: `${scheme}:///${key}`,
|
|
53
|
+
name: key,
|
|
54
|
+
mimeType: MARKDOWN_MIME_TYPE,
|
|
55
|
+
})),
|
|
56
|
+
}),
|
|
57
|
+
complete: {
|
|
58
|
+
[variable]: async (value) => {
|
|
59
|
+
const needle = value.toLowerCase();
|
|
60
|
+
return (await list()).filter((key) =>
|
|
61
|
+
key.toLowerCase().includes(needle),
|
|
62
|
+
);
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
}),
|
|
66
|
+
{ title, description, mimeType: MARKDOWN_MIME_TYPE },
|
|
67
|
+
async (uri, variables) => {
|
|
68
|
+
const key = templateVarToPath(variables[variable]);
|
|
69
|
+
const text = await read(key);
|
|
70
|
+
if (text === null) {
|
|
71
|
+
throw new Error(`${notFoundLabel} not found: ${key}`);
|
|
72
|
+
}
|
|
73
|
+
return {
|
|
74
|
+
contents: [{ uri: uri.href, mimeType: MARKDOWN_MIME_TYPE, text }],
|
|
75
|
+
};
|
|
76
|
+
},
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async function readDocResource(path: string): Promise<string | null> {
|
|
81
|
+
const sanitized = sanitizePath(path);
|
|
82
|
+
const mdx = await readMDXFileSafe(
|
|
83
|
+
join(DOCS_PATH, `${sanitized}${MDX_EXTENSION}`),
|
|
84
|
+
);
|
|
85
|
+
return mdx ? formatMDXContent(mdx) : null;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function registerResources(server: McpServer): void {
|
|
89
|
+
registerMarkdownResource(server, {
|
|
90
|
+
name: "assistant-ui-docs",
|
|
91
|
+
scheme: DOCS_SCHEME,
|
|
92
|
+
variable: "path",
|
|
93
|
+
title: "assistant-ui Documentation",
|
|
94
|
+
description:
|
|
95
|
+
"Individual assistant-ui documentation pages, readable as markdown by path.",
|
|
96
|
+
notFoundLabel: "Documentation",
|
|
97
|
+
list: getAvailableDocFiles,
|
|
98
|
+
read: readDocResource,
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
registerMarkdownResource(server, {
|
|
102
|
+
name: "assistant-ui-examples",
|
|
103
|
+
scheme: EXAMPLE_SCHEME,
|
|
104
|
+
variable: "name",
|
|
105
|
+
title: "assistant-ui Examples",
|
|
106
|
+
description:
|
|
107
|
+
"Complete assistant-ui example projects, readable as markdown.",
|
|
108
|
+
notFoundLabel: "Example",
|
|
109
|
+
list: listCodeExamples,
|
|
110
|
+
read: readCodeExample,
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
logger.debug("Registered docs and examples resources");
|
|
114
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { z } from "zod/v3";
|
|
2
|
+
import { logger } from "../utils/logger.js";
|
|
3
|
+
import { formatMCPResponse } from "../utils/mcp-format.js";
|
|
4
|
+
import { searchDocs } from "../utils/search.js";
|
|
5
|
+
|
|
6
|
+
const searchInputSchema = z.object({
|
|
7
|
+
query: z
|
|
8
|
+
.string()
|
|
9
|
+
.min(1)
|
|
10
|
+
.describe("Keyword(s) to search assistant-ui documentation for."),
|
|
11
|
+
limit: z
|
|
12
|
+
.number()
|
|
13
|
+
.int()
|
|
14
|
+
.min(1)
|
|
15
|
+
.max(25)
|
|
16
|
+
.default(10)
|
|
17
|
+
.describe("Maximum number of results to return (default 10)."),
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
export const searchTools = {
|
|
21
|
+
name: "assistantUISearch",
|
|
22
|
+
description:
|
|
23
|
+
"Search assistant-ui documentation by keyword. Returns ranked matches with their doc path, title, and a snippet. Fetch full content with assistantUIDocs using a returned path.",
|
|
24
|
+
parameters: searchInputSchema.shape,
|
|
25
|
+
execute: async ({ query, limit }: z.infer<typeof searchInputSchema>) => {
|
|
26
|
+
logger.info(`Searching documentation for: ${query}`);
|
|
27
|
+
try {
|
|
28
|
+
const results = await searchDocs(query, limit);
|
|
29
|
+
if (results.length === 0) {
|
|
30
|
+
return formatMCPResponse({
|
|
31
|
+
query,
|
|
32
|
+
results: [],
|
|
33
|
+
total: 0,
|
|
34
|
+
hint: 'No matches. Use assistantUIDocs with "/" to list all sections.',
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
return formatMCPResponse({ query, results, total: results.length });
|
|
38
|
+
} catch (error) {
|
|
39
|
+
logger.error("Failed to search documentation", error);
|
|
40
|
+
return formatMCPResponse({
|
|
41
|
+
error: "Failed to search documentation",
|
|
42
|
+
message: error instanceof Error ? error.message : String(error),
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { server } from "../../index.js";
|
|
3
|
+
|
|
4
|
+
function handler(method: string) {
|
|
5
|
+
const handlers = (server as any).server._requestHandlers;
|
|
6
|
+
const h = handlers.get(method);
|
|
7
|
+
if (!h) throw new Error(`No handler for ${method}`);
|
|
8
|
+
return h;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
async function complete(uri: string, name: string, value: string) {
|
|
12
|
+
return handler("completion/complete")(
|
|
13
|
+
{
|
|
14
|
+
method: "completion/complete",
|
|
15
|
+
params: { ref: { type: "ref/resource", uri }, argument: { name, value } },
|
|
16
|
+
},
|
|
17
|
+
{},
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
describe("resource argument completions", () => {
|
|
22
|
+
it("suggests doc paths matching the partial value", async () => {
|
|
23
|
+
const res = await complete("aui-docs:///{+path}", "path", "api");
|
|
24
|
+
expect(res.completion.values.length).toBeGreaterThan(0);
|
|
25
|
+
expect(
|
|
26
|
+
res.completion.values.every((v: string) =>
|
|
27
|
+
v.toLowerCase().includes("api"),
|
|
28
|
+
),
|
|
29
|
+
).toBe(true);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it("suggests example names matching the partial value", async () => {
|
|
33
|
+
const res = await complete("aui-example:///{+name}", "name", "with");
|
|
34
|
+
expect(res.completion.values.length).toBeGreaterThan(0);
|
|
35
|
+
expect(
|
|
36
|
+
res.completion.values.every((v: string) =>
|
|
37
|
+
v.toLowerCase().includes("with"),
|
|
38
|
+
),
|
|
39
|
+
).toBe(true);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("returns no values for a nonsense partial", async () => {
|
|
43
|
+
const res = await complete("aui-docs:///{+path}", "path", "zzzqqxnope");
|
|
44
|
+
expect(res.completion.values).toHaveLength(0);
|
|
45
|
+
});
|
|
46
|
+
});
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from "vitest";
|
|
2
|
+
|
|
3
|
+
vi.mock("../../utils/paths.js", async (importOriginal) => ({
|
|
4
|
+
...(await importOriginal<typeof import("../../utils/paths.js")>()),
|
|
5
|
+
listDirContents: vi.fn(async () => ({
|
|
6
|
+
directories: [],
|
|
7
|
+
files: ["first.mdx", "second.mdx"],
|
|
8
|
+
})),
|
|
9
|
+
}));
|
|
10
|
+
|
|
11
|
+
vi.mock("node:fs/promises", async (importOriginal) => {
|
|
12
|
+
const actual = await importOriginal<typeof import("node:fs/promises")>();
|
|
13
|
+
return {
|
|
14
|
+
...actual,
|
|
15
|
+
stat: vi.fn(async (path: string) => ({
|
|
16
|
+
isFile: () => path.endsWith(".mdx"),
|
|
17
|
+
isDirectory: () => !path.endsWith(".mdx"),
|
|
18
|
+
size: 600 * 1024,
|
|
19
|
+
})),
|
|
20
|
+
};
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
vi.mock("../../utils/mdx.js", async (importOriginal) => ({
|
|
24
|
+
...(await importOriginal<typeof import("../../utils/mdx.js")>()),
|
|
25
|
+
readMDXFile: vi.fn(async () => ({
|
|
26
|
+
content: "x".repeat(600 * 1024),
|
|
27
|
+
frontmatter: {},
|
|
28
|
+
})),
|
|
29
|
+
formatMDXContent: (mdx: { content: string }) => mdx.content,
|
|
30
|
+
}));
|
|
31
|
+
|
|
32
|
+
import { docsTools } from "../docs.js";
|
|
33
|
+
|
|
34
|
+
function parse(result: { content: Array<{ text: string }> }) {
|
|
35
|
+
return JSON.parse(result.content[0]!.text);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
describe("assistantUIDocs directory aggregate size cap", () => {
|
|
39
|
+
it("omits inlined content and returns a hint when a directory exceeds the cap", async () => {
|
|
40
|
+
const result = await docsTools.execute({
|
|
41
|
+
paths: ["(reference)/api-reference/primitives"],
|
|
42
|
+
});
|
|
43
|
+
const parsed = parse(result);
|
|
44
|
+
|
|
45
|
+
expect(parsed.type).toBe("directory");
|
|
46
|
+
expect(parsed.files).toEqual(["first", "second"]);
|
|
47
|
+
expect(parsed.content).toBeUndefined();
|
|
48
|
+
expect(parsed.hint).toContain("exceeds");
|
|
49
|
+
});
|
|
50
|
+
});
|
|
@@ -91,6 +91,26 @@ describe("assistantUIDocs", () => {
|
|
|
91
91
|
expect(result.content).toContain("assistant-ui");
|
|
92
92
|
});
|
|
93
93
|
|
|
94
|
+
it("includes title and excerpt on a file response", async () => {
|
|
95
|
+
const result = await testContext.callTool("assistantUIDocs", {
|
|
96
|
+
paths: ["(docs)/index"],
|
|
97
|
+
});
|
|
98
|
+
expect(result.type).toBe("file");
|
|
99
|
+
expect(result.title ?? result.excerpt).toBeDefined();
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it("includes per-file summaries on a directory listing", async () => {
|
|
103
|
+
const result = await testContext.callTool("assistantUIDocs", {
|
|
104
|
+
paths: ["(reference)/api-reference/primitives"],
|
|
105
|
+
});
|
|
106
|
+
expect(result.type).toBe("directory");
|
|
107
|
+
expect(Array.isArray(result.summaries)).toBe(true);
|
|
108
|
+
expect(result.summaries.length).toBeGreaterThan(0);
|
|
109
|
+
const summary = result.summaries[0];
|
|
110
|
+
expect(summary.name).toBeDefined();
|
|
111
|
+
expect(summary.title ?? summary.excerpt).toBeDefined();
|
|
112
|
+
});
|
|
113
|
+
|
|
94
114
|
it("should skip symlinks and large files", async () => {
|
|
95
115
|
const mockedLstat = vi.mocked(fs.lstat);
|
|
96
116
|
|
|
@@ -19,20 +19,20 @@ describe("assistantUIExamples", () => {
|
|
|
19
19
|
expect(result.examples).toBeDefined();
|
|
20
20
|
expect(Array.isArray(result.examples)).toBe(true);
|
|
21
21
|
expect(result.examples.length).toBeGreaterThan(0);
|
|
22
|
-
expect(result.examples).toContain("with-ai-sdk-
|
|
22
|
+
expect(result.examples).toContain("with-ai-sdk-v7");
|
|
23
23
|
expect(result.examples).toContain("with-langgraph");
|
|
24
24
|
expect(result.total).toBe(result.examples.length);
|
|
25
25
|
});
|
|
26
26
|
|
|
27
27
|
it("should retrieve specific example code", async () => {
|
|
28
28
|
const result = await testContext.callTool("assistantUIExamples", {
|
|
29
|
-
example: "with-ai-sdk-
|
|
29
|
+
example: "with-ai-sdk-v7",
|
|
30
30
|
});
|
|
31
31
|
|
|
32
32
|
expect(result.type).toBe("example");
|
|
33
|
-
expect(result.name).toBe("with-ai-sdk-
|
|
33
|
+
expect(result.name).toBe("with-ai-sdk-v7");
|
|
34
34
|
expect(result.content).toBeDefined();
|
|
35
|
-
expect(result.content).toContain("# Example: with-ai-sdk-
|
|
35
|
+
expect(result.content).toContain("# Example: with-ai-sdk-v7");
|
|
36
36
|
expect(result.content).toContain("app/api/chat/route.ts");
|
|
37
37
|
expect(result.content).toContain("streamText");
|
|
38
38
|
});
|
|
@@ -50,7 +50,7 @@ describe("assistantUIExamples", () => {
|
|
|
50
50
|
|
|
51
51
|
it("should include all files in example", async () => {
|
|
52
52
|
const result = await testContext.callTool("assistantUIExamples", {
|
|
53
|
-
example: "with-ai-sdk-
|
|
53
|
+
example: "with-ai-sdk-v7",
|
|
54
54
|
});
|
|
55
55
|
|
|
56
56
|
expect(result.content).toContain("package.json");
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { getAvailableDocFiles } from "../../utils/paths.js";
|
|
3
|
+
import { listCodeExamples } from "../examples.js";
|
|
4
|
+
|
|
5
|
+
describe("listing caches", () => {
|
|
6
|
+
it("caches the doc file listing (same instance on repeat calls)", async () => {
|
|
7
|
+
const first = await getAvailableDocFiles();
|
|
8
|
+
const second = await getAvailableDocFiles();
|
|
9
|
+
expect(second).toBe(first);
|
|
10
|
+
expect(first.length).toBeGreaterThan(0);
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it("caches the example listing (same instance on repeat calls)", async () => {
|
|
14
|
+
const first = await listCodeExamples();
|
|
15
|
+
const second = await listCodeExamples();
|
|
16
|
+
expect(second).toBe(first);
|
|
17
|
+
expect(first.length).toBeGreaterThan(0);
|
|
18
|
+
});
|
|
19
|
+
});
|
|
@@ -4,9 +4,13 @@ import {
|
|
|
4
4
|
InitializeRequestSchema,
|
|
5
5
|
ListToolsRequestSchema,
|
|
6
6
|
CallToolRequestSchema,
|
|
7
|
+
ListPromptsRequestSchema,
|
|
8
|
+
GetPromptRequestSchema,
|
|
7
9
|
type InitializeRequest,
|
|
8
10
|
type ListToolsRequest,
|
|
9
11
|
type CallToolRequest,
|
|
12
|
+
type ListPromptsRequest,
|
|
13
|
+
type GetPromptRequest,
|
|
10
14
|
} from "@modelcontextprotocol/sdk/types.js";
|
|
11
15
|
|
|
12
16
|
describe("MCP Protocol Integration", () => {
|
|
@@ -55,7 +59,7 @@ describe("MCP Protocol Integration", () => {
|
|
|
55
59
|
|
|
56
60
|
expect(result).toBeDefined();
|
|
57
61
|
expect(result.tools).toBeInstanceOf(Array);
|
|
58
|
-
expect(result.tools).toHaveLength(
|
|
62
|
+
expect(result.tools).toHaveLength(6);
|
|
59
63
|
|
|
60
64
|
// Check the tools have proper JSON schemas
|
|
61
65
|
const docsTool = result.tools.find(
|
|
@@ -74,6 +78,14 @@ describe("MCP Protocol Integration", () => {
|
|
|
74
78
|
expect(examplesTool.inputSchema.type).toBe("object");
|
|
75
79
|
expect(examplesTool.inputSchema.properties).toBeDefined();
|
|
76
80
|
|
|
81
|
+
const searchTool = result.tools.find(
|
|
82
|
+
(t: any) => t.name === "assistantUISearch",
|
|
83
|
+
);
|
|
84
|
+
expect(searchTool).toBeDefined();
|
|
85
|
+
expect(searchTool.inputSchema).toBeDefined();
|
|
86
|
+
expect(searchTool.inputSchema.type).toBe("object");
|
|
87
|
+
expect(searchTool.inputSchema.properties).toBeDefined();
|
|
88
|
+
|
|
77
89
|
// registerTool metadata is surfaced on tools/list: `title` is a
|
|
78
90
|
// top-level field, `annotations` carries only the hint flags.
|
|
79
91
|
expect(docsTool.title).toBe("assistant-ui Documentation");
|
|
@@ -82,6 +94,33 @@ describe("MCP Protocol Integration", () => {
|
|
|
82
94
|
expect(examplesTool.title).toBe("assistant-ui Examples");
|
|
83
95
|
expect(examplesTool.annotations?.readOnlyHint).toBe(true);
|
|
84
96
|
expect(examplesTool.annotations?.openWorldHint).toBe(false);
|
|
97
|
+
expect(searchTool.title).toBe("Search assistant-ui Documentation");
|
|
98
|
+
expect(searchTool.annotations?.readOnlyHint).toBe(true);
|
|
99
|
+
expect(searchTool.annotations?.openWorldHint).toBe(false);
|
|
100
|
+
|
|
101
|
+
const xuluxListTool = result.tools.find(
|
|
102
|
+
(t: any) => t.name === "assistantUITemplates",
|
|
103
|
+
);
|
|
104
|
+
expect(xuluxListTool).toBeDefined();
|
|
105
|
+
expect(xuluxListTool.title).toBe("assistant-ui Templates");
|
|
106
|
+
expect(xuluxListTool.annotations?.readOnlyHint).toBe(true);
|
|
107
|
+
expect(xuluxListTool.annotations?.openWorldHint).toBe(true);
|
|
108
|
+
|
|
109
|
+
const xuluxDetailsTool = result.tools.find(
|
|
110
|
+
(t: any) => t.name === "assistantUITemplateDetails",
|
|
111
|
+
);
|
|
112
|
+
expect(xuluxDetailsTool).toBeDefined();
|
|
113
|
+
expect(xuluxDetailsTool.title).toBe("assistant-ui Template Details");
|
|
114
|
+
expect(xuluxDetailsTool.annotations?.readOnlyHint).toBe(true);
|
|
115
|
+
expect(xuluxDetailsTool.annotations?.openWorldHint).toBe(true);
|
|
116
|
+
|
|
117
|
+
const xuluxPreviewTool = result.tools.find(
|
|
118
|
+
(t: any) => t.name === "assistantUITemplatePreview",
|
|
119
|
+
);
|
|
120
|
+
expect(xuluxPreviewTool).toBeDefined();
|
|
121
|
+
expect(xuluxPreviewTool.title).toBe("assistant-ui Template Preview URLs");
|
|
122
|
+
expect(xuluxPreviewTool.annotations?.readOnlyHint).toBe(false);
|
|
123
|
+
expect(xuluxPreviewTool.annotations?.openWorldHint).toBe(true);
|
|
85
124
|
});
|
|
86
125
|
|
|
87
126
|
it("should handle CallTool request for assistantUIDocs", async () => {
|
|
@@ -137,4 +176,56 @@ describe("MCP Protocol Integration", () => {
|
|
|
137
176
|
expect(result.content).toBeDefined();
|
|
138
177
|
expect(result.content[0].type).toBe("text");
|
|
139
178
|
});
|
|
179
|
+
|
|
180
|
+
it("should handle ListPrompts request", async () => {
|
|
181
|
+
const request: ListPromptsRequest = {
|
|
182
|
+
method: "prompts/list",
|
|
183
|
+
params: {},
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
const parsed = ListPromptsRequestSchema.parse(request);
|
|
187
|
+
expect(parsed).toBeDefined();
|
|
188
|
+
|
|
189
|
+
const handlers = (server as any).server._requestHandlers;
|
|
190
|
+
expect(handlers.get("prompts/list")).toBeDefined();
|
|
191
|
+
|
|
192
|
+
const handler = handlers.get("prompts/list");
|
|
193
|
+
const result = await handler(parsed, {});
|
|
194
|
+
|
|
195
|
+
expect(result.prompts).toBeInstanceOf(Array);
|
|
196
|
+
const prompt = result.prompts.find(
|
|
197
|
+
(p: any) => p.name === "assistant-ui-template-workflow",
|
|
198
|
+
);
|
|
199
|
+
expect(prompt).toBeDefined();
|
|
200
|
+
expect(prompt.title).toBe("assistant-ui Template Workflow");
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
it("should handle GetPrompt request for assistant-ui-template-workflow", async () => {
|
|
204
|
+
const request: GetPromptRequest = {
|
|
205
|
+
method: "prompts/get",
|
|
206
|
+
params: {
|
|
207
|
+
name: "assistant-ui-template-workflow",
|
|
208
|
+
arguments: {},
|
|
209
|
+
},
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
const parsed = GetPromptRequestSchema.parse(request);
|
|
213
|
+
expect(parsed).toBeDefined();
|
|
214
|
+
|
|
215
|
+
const handlers = (server as any).server._requestHandlers;
|
|
216
|
+
expect(handlers.get("prompts/get")).toBeDefined();
|
|
217
|
+
|
|
218
|
+
const handler = handlers.get("prompts/get");
|
|
219
|
+
const result = await handler(parsed, {});
|
|
220
|
+
|
|
221
|
+
expect(result.messages).toHaveLength(1);
|
|
222
|
+
expect(result.messages[0].content.type).toBe("text");
|
|
223
|
+
expect(result.messages[0].content.text).toContain("assistantUITemplates");
|
|
224
|
+
expect(result.messages[0].content.text).toContain(
|
|
225
|
+
"assistantUITemplateDetails",
|
|
226
|
+
);
|
|
227
|
+
expect(result.messages[0].content.text).toContain(
|
|
228
|
+
"assistantUITemplatePreview",
|
|
229
|
+
);
|
|
230
|
+
});
|
|
140
231
|
});
|