@assistant-ui/mcp-docs-server 0.1.38 → 0.2.0
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 +11 -12
- package/.docs/organized/code-examples/with-a2a.md +18 -13
- package/.docs/organized/code-examples/with-ag-ui.md +19 -14
- package/.docs/organized/code-examples/{with-ai-sdk-v6.md → with-ai-sdk-v7.md} +34 -23
- package/.docs/organized/code-examples/with-artifacts.md +473 -141
- package/.docs/organized/code-examples/with-assistant-transport.md +17 -10
- package/.docs/organized/code-examples/with-browser-extension.md +17 -10
- package/.docs/organized/code-examples/with-chain-of-thought.md +21 -14
- package/.docs/organized/code-examples/with-cloud-standalone.md +12 -11
- package/.docs/organized/code-examples/with-cloud.md +20 -15
- package/.docs/organized/code-examples/with-custom-thread-list.md +19 -12
- package/.docs/organized/code-examples/with-elevenlabs-conversational.md +22 -15
- package/.docs/organized/code-examples/with-elevenlabs-scribe.md +22 -15
- package/.docs/organized/code-examples/with-eve.md +18 -11
- package/.docs/organized/code-examples/with-expo.md +35 -52
- package/.docs/organized/code-examples/with-external-store.md +18 -13
- package/.docs/organized/code-examples/with-ffmpeg.md +20 -15
- package/.docs/organized/code-examples/with-generative-ui.md +22 -17
- package/.docs/organized/code-examples/with-google-adk.md +18 -11
- package/.docs/organized/code-examples/with-heat-graph.md +10 -11
- package/.docs/organized/code-examples/with-image-generation.md +19 -12
- package/.docs/organized/code-examples/with-interactables.md +21 -17
- package/.docs/organized/code-examples/with-langchain.md +19 -12
- package/.docs/organized/code-examples/with-langgraph.md +19 -12
- package/.docs/organized/code-examples/with-livekit.md +23 -16
- package/.docs/organized/code-examples/with-mcp.md +46 -28
- package/.docs/organized/code-examples/with-opencode.md +25 -23
- package/.docs/organized/code-examples/with-pi.md +54 -19
- package/.docs/organized/code-examples/with-react-hook-form.md +21 -16
- package/.docs/organized/code-examples/with-react-ink-web.md +9 -9
- package/.docs/organized/code-examples/with-react-ink.md +4 -4
- package/.docs/organized/code-examples/with-react-router.md +22 -17
- package/.docs/organized/code-examples/with-resumable-stream.md +21 -14
- package/.docs/organized/code-examples/with-store.md +10 -11
- package/.docs/organized/code-examples/with-tanstack.md +19 -13
- package/.docs/organized/code-examples/with-tap-runtime.md +18 -13
- package/.docs/organized/code-examples/with-virtualized-thread.md +19 -14
- package/.docs/raw/docs/(docs)/base-ui.mdx +39 -0
- package/.docs/raw/docs/(docs)/cli.mdx +19 -1
- package/.docs/raw/docs/(docs)/devtools.mdx +7 -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/a2ui.mdx +40 -0
- 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 +22 -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/hooks/primitives.mdx +19 -420
- package/.docs/raw/docs/(reference)/api-reference/hooks/state.mdx +4 -1
- package/.docs/raw/docs/(reference)/api-reference/integrations/index.mdx +4 -1
- package/.docs/raw/docs/(reference)/api-reference/integrations/react-ai-sdk.mdx +25 -2
- package/.docs/raw/docs/(reference)/api-reference/integrations/react-data-stream.mdx +37 -0
- package/.docs/raw/docs/(reference)/api-reference/model-context/context.mdx +1 -9
- package/.docs/raw/docs/(reference)/api-reference/overview.mdx +1 -0
- package/.docs/raw/docs/(reference)/api-reference/primitives/assistant-if.mdx +14 -31
- 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/copilots/model-context.mdx +1 -1
- package/.docs/raw/docs/copilots/motivation.mdx +1 -1
- package/.docs/raw/docs/guides/attachments.mdx +3 -3
- package/.docs/raw/docs/guides/branching.mdx +2 -2
- package/.docs/raw/docs/guides/chatgpt-subscription.mdx +108 -0
- package/.docs/raw/docs/guides/context-api.mdx +89 -111
- package/.docs/raw/docs/guides/dictation.mdx +185 -257
- package/.docs/raw/docs/guides/editing.mdx +5 -5
- package/.docs/raw/docs/guides/electron.mdx +369 -0
- package/.docs/raw/docs/guides/index.mdx +20 -0
- package/.docs/raw/docs/guides/mentions.mdx +31 -3
- package/.docs/raw/docs/guides/quoting.mdx +3 -3
- package/.docs/raw/docs/guides/resumable-stream-deployment.mdx +2 -2
- 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/hooks.mdx +3 -3
- package/.docs/raw/docs/ink/primitives.mdx +49 -8
- package/.docs/raw/docs/integrations/auth/better-auth.mdx +2 -2
- package/.docs/raw/docs/integrations/auth/clerk.mdx +2 -2
- package/.docs/raw/docs/integrations/auth/next-auth.mdx +3 -3
- package/.docs/raw/docs/integrations/frameworks/ai-sdk.mdx +10 -4
- 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/observability/helicone.mdx +1 -1
- 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 +36 -9
- package/.docs/raw/docs/migrations/index.mdx +50 -0
- package/.docs/raw/docs/migrations/toolkit-tools.mdx +4 -2
- package/.docs/raw/docs/migrations/v0-15.mdx +156 -0
- package/.docs/raw/docs/primitives/chain-of-thought.mdx +6 -1
- package/.docs/raw/docs/primitives/composer.mdx +17 -1
- package/.docs/raw/docs/primitives/selection-toolbar.mdx +25 -0
- package/.docs/raw/docs/primitives/thread-list.mdx +2 -2
- package/.docs/raw/docs/react-native/hooks.mdx +3 -3
- package/.docs/raw/docs/react-native/index.mdx +2 -2
- package/.docs/raw/docs/react-native/primitives.mdx +62 -5
- package/.docs/raw/docs/runtimes/ag-ui/agent-state.mdx +124 -0
- package/.docs/raw/docs/runtimes/ag-ui/runtime-options.mdx +10 -1
- package/.docs/raw/docs/runtimes/ai-sdk/overview.mdx +14 -5
- package/.docs/raw/docs/runtimes/ai-sdk/v4-legacy.mdx +15 -15
- package/.docs/raw/docs/runtimes/ai-sdk/v5-legacy.mdx +8 -8
- package/.docs/raw/docs/runtimes/ai-sdk/{v6.mdx → v6-legacy.mdx} +11 -9
- 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/concepts/threads.mdx +10 -10
- package/.docs/raw/docs/runtimes/custom/assistant-transport.mdx +2 -2
- package/.docs/raw/docs/runtimes/custom/data-stream.mdx +10 -19
- package/.docs/raw/docs/runtimes/custom/external-store.mdx +2 -2
- package/.docs/raw/docs/runtimes/custom/local-runtime.mdx +5 -3
- package/.docs/raw/docs/runtimes/eve/overview.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/langgraph/overview.mdx +1 -1
- package/.docs/raw/docs/runtimes/opencode/hooks.mdx +3 -1
- package/.docs/raw/docs/tools/a2ui.mdx +107 -0
- package/.docs/raw/docs/tools/backend.mdx +6 -3
- package/.docs/raw/docs/tools/defining-tools.mdx +7 -1
- package/.docs/raw/docs/tools/generative-ui.mdx +60 -2
- package/.docs/raw/docs/tools/interactables-legacy.mdx +4 -4
- package/.docs/raw/docs/tools/interactables.mdx +3 -3
- package/.docs/raw/docs/tools/mcp-apps.mdx +90 -13
- package/.docs/raw/docs/tools/mcp.mdx +100 -3
- package/.docs/raw/docs/tools/tool-ui.mdx +6 -4
- package/.docs/raw/docs/tools/user-managed-mcp.mdx +77 -9
- 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 +4 -2
- package/.docs/raw/docs/ui/model-selector.mdx +33 -3
- package/.docs/raw/docs/ui/part-grouping.mdx +0 -4
- package/.docs/raw/docs/ui/reasoning.mdx +1 -1
- 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/dist/constants.d.ts.map +1 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +41 -2
- package/dist/index.js.map +1 -1
- package/dist/prepare-docs/code-examples.d.ts.map +1 -1
- package/dist/prepare-docs/code-examples.js.map +1 -1
- package/dist/prepare-docs/copy-raw.d.ts.map +1 -1
- package/dist/prepare-docs/prepare.d.ts +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/stdio.d.ts +1 -1
- package/dist/tools/docs.d.ts +8 -14
- package/dist/tools/docs.d.ts.map +1 -1
- package/dist/tools/docs.js +26 -10
- package/dist/tools/docs.js.map +1 -1
- package/dist/tools/examples.d.ts +6 -12
- package/dist/tools/examples.d.ts.map +1 -1
- package/dist/tools/examples.js +11 -8
- package/dist/tools/examples.js.map +1 -1
- package/dist/tools/resources.d.ts +1 -2
- package/dist/tools/resources.d.ts.map +1 -1
- package/dist/tools/resources.js +1 -1
- package/dist/tools/resources.js.map +1 -1
- package/dist/tools/search.d.ts +6 -15
- package/dist/tools/search.d.ts.map +1 -1
- package/dist/tools/search.js +2 -2
- package/dist/tools/search.js.map +1 -1
- package/dist/tools/tests/mcp-test-client.d.ts +15 -0
- package/dist/tools/tests/mcp-test-client.d.ts.map +1 -0
- package/dist/tools/tests/mcp-test-client.js +68 -0
- package/dist/tools/tests/mcp-test-client.js.map +1 -0
- package/dist/tools/tests/test-setup.d.ts.map +1 -1
- package/dist/tools/tests/test-setup.js +5 -1
- package/dist/tools/tests/test-setup.js.map +1 -1
- package/dist/tools/xulux-templates.d.ts +58 -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.map +1 -1
- package/dist/utils/paths.d.ts +1 -1
- package/dist/utils/paths.d.ts.map +1 -1
- package/dist/utils/paths.js +3 -1
- package/dist/utils/paths.js.map +1 -1
- package/dist/utils/search.d.ts.map +1 -1
- package/dist/utils/security.d.ts.map +1 -1
- package/dist/utils/security.js.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 +7 -6
- package/src/index.ts +55 -2
- package/src/prompts/xulux-playground.ts +36 -0
- package/src/tools/docs.ts +27 -5
- package/src/tools/examples.ts +17 -12
- package/src/tools/resources.ts +1 -4
- package/src/tools/search.ts +2 -2
- package/src/tools/tests/completions.test.ts +40 -26
- package/src/tools/tests/docs.test.ts +20 -0
- package/src/tools/tests/examples.test.ts +5 -5
- package/src/tools/tests/integration.test.ts +3 -4
- package/src/tools/tests/listings-cache.test.ts +19 -0
- package/src/tools/tests/mcp-protocol.test.ts +173 -108
- package/src/tools/tests/mcp-test-client.ts +111 -0
- package/src/tools/tests/resources.test.ts +97 -66
- package/src/tools/tests/test-setup.ts +8 -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/paths.ts +4 -1
- 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/docs/(reference)/api-reference/hooks/utilities.mdx +0 -464
|
@@ -1,102 +1,160 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { server } from "../../index.js";
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
3
2
|
import {
|
|
3
|
+
CallToolRequestSchema,
|
|
4
|
+
GetPromptRequestSchema,
|
|
4
5
|
InitializeRequestSchema,
|
|
6
|
+
ListPromptsRequestSchema,
|
|
5
7
|
ListToolsRequestSchema,
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
} from "@modelcontextprotocol/core";
|
|
9
|
+
import { server } from "../../index.js";
|
|
10
|
+
import { createMcpTestClient, type McpTestClient } from "./mcp-test-client.js";
|
|
11
|
+
|
|
12
|
+
type Tool = {
|
|
13
|
+
name: string;
|
|
14
|
+
title?: string;
|
|
15
|
+
annotations?: {
|
|
16
|
+
readOnlyHint?: boolean;
|
|
17
|
+
openWorldHint?: boolean;
|
|
18
|
+
};
|
|
19
|
+
inputSchema: {
|
|
20
|
+
type?: string;
|
|
21
|
+
properties?: Record<string, { description?: string }>;
|
|
22
|
+
required?: string[];
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
type ToolListResult = {
|
|
27
|
+
tools: Tool[];
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
type ToolCallResult = {
|
|
31
|
+
content: Array<{
|
|
32
|
+
type: string;
|
|
33
|
+
}>;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
type PromptListResult = {
|
|
37
|
+
prompts: Array<{
|
|
38
|
+
name: string;
|
|
39
|
+
title?: string;
|
|
40
|
+
}>;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
type PromptGetResult = {
|
|
44
|
+
messages: Array<{
|
|
45
|
+
content: {
|
|
46
|
+
type: string;
|
|
47
|
+
text?: string;
|
|
48
|
+
};
|
|
49
|
+
}>;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
type InitializeResult = {
|
|
53
|
+
protocolVersion: string;
|
|
54
|
+
serverInfo: {
|
|
55
|
+
name: string;
|
|
56
|
+
};
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
function requireTool(tools: Tool[], name: string): Tool {
|
|
60
|
+
const tool = tools.find((candidate) => candidate.name === name);
|
|
61
|
+
expect(tool).toBeDefined();
|
|
62
|
+
if (!tool) throw new Error(`Missing tool: ${name}`);
|
|
63
|
+
return tool;
|
|
64
|
+
}
|
|
11
65
|
|
|
12
66
|
describe("MCP Protocol Integration", () => {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
67
|
+
let client: McpTestClient;
|
|
68
|
+
let initializeResult: Promise<InitializeResult>;
|
|
69
|
+
|
|
70
|
+
beforeEach(async () => {
|
|
71
|
+
client = await createMcpTestClient(server);
|
|
72
|
+
initializeResult = client.initialize() as Promise<InitializeResult>;
|
|
73
|
+
await initializeResult;
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
afterEach(async () => {
|
|
77
|
+
await client?.close();
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it("handles Initialize requests", async () => {
|
|
81
|
+
const request = {
|
|
17
82
|
method: "initialize",
|
|
18
83
|
params: {
|
|
19
|
-
protocolVersion: "
|
|
84
|
+
protocolVersion: "2025-11-25",
|
|
20
85
|
capabilities: {},
|
|
21
86
|
clientInfo: {
|
|
22
|
-
name: "
|
|
87
|
+
name: "mcp-docs-server-tests",
|
|
23
88
|
version: "1.0.0",
|
|
24
89
|
},
|
|
25
90
|
},
|
|
26
91
|
};
|
|
27
92
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
const handlers = (server as any).server._requestHandlers;
|
|
34
|
-
expect(handlers).toBeDefined();
|
|
35
|
-
expect(handlers.get("initialize")).toBeDefined();
|
|
93
|
+
expect(InitializeRequestSchema.parse(request)).toBeDefined();
|
|
94
|
+
await expect(initializeResult).resolves.toMatchObject({
|
|
95
|
+
protocolVersion: "2025-11-25",
|
|
96
|
+
serverInfo: { name: "assistant-ui-docs" },
|
|
97
|
+
});
|
|
36
98
|
});
|
|
37
99
|
|
|
38
|
-
it("
|
|
39
|
-
const request
|
|
100
|
+
it("lists tool metadata and JSON schemas", async () => {
|
|
101
|
+
const request = ListToolsRequestSchema.parse({
|
|
40
102
|
method: "tools/list",
|
|
41
103
|
params: {},
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
// Parse and validate the request
|
|
45
|
-
const parsed = ListToolsRequestSchema.parse(request);
|
|
46
|
-
expect(parsed).toBeDefined();
|
|
47
|
-
|
|
48
|
-
// The server should have a tools/list handler
|
|
49
|
-
const handlers = (server as any).server._requestHandlers;
|
|
50
|
-
expect(handlers.get("tools/list")).toBeDefined();
|
|
51
|
-
|
|
52
|
-
// Call the handler
|
|
53
|
-
const handler = handlers.get("tools/list");
|
|
54
|
-
const result = await handler(parsed, {});
|
|
104
|
+
});
|
|
105
|
+
const result = await client.request<ToolListResult>(request);
|
|
55
106
|
|
|
56
|
-
expect(result).
|
|
57
|
-
expect(result.tools).toBeInstanceOf(Array);
|
|
58
|
-
expect(result.tools).toHaveLength(3);
|
|
107
|
+
expect(result.tools).toHaveLength(6);
|
|
59
108
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
109
|
+
for (const expected of [
|
|
110
|
+
{
|
|
111
|
+
name: "assistantUIDocs",
|
|
112
|
+
title: "assistant-ui Documentation",
|
|
113
|
+
annotations: { readOnlyHint: true, openWorldHint: false },
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
name: "assistantUIExamples",
|
|
117
|
+
title: "assistant-ui Examples",
|
|
118
|
+
annotations: { readOnlyHint: true, openWorldHint: false },
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
name: "assistantUISearch",
|
|
122
|
+
title: "Search assistant-ui Documentation",
|
|
123
|
+
annotations: { readOnlyHint: true, openWorldHint: false },
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
name: "assistantUITemplates",
|
|
127
|
+
title: "assistant-ui Templates",
|
|
128
|
+
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
name: "assistantUITemplateDetails",
|
|
132
|
+
title: "assistant-ui Template Details",
|
|
133
|
+
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
name: "assistantUITemplatePreview",
|
|
137
|
+
title: "assistant-ui Template Preview URLs",
|
|
138
|
+
annotations: { readOnlyHint: false, openWorldHint: true },
|
|
139
|
+
},
|
|
140
|
+
]) {
|
|
141
|
+
const tool = requireTool(result.tools, expected.name);
|
|
142
|
+
|
|
143
|
+
expect(tool).toMatchObject({
|
|
144
|
+
title: expected.title,
|
|
145
|
+
annotations: expected.annotations,
|
|
146
|
+
});
|
|
147
|
+
expect(tool.inputSchema.type).toBe("object");
|
|
148
|
+
expect(tool.inputSchema.properties).toBeDefined();
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const search = requireTool(result.tools, "assistantUISearch");
|
|
152
|
+
expect(search.inputSchema.required ?? []).not.toContain("limit");
|
|
153
|
+
expect(search.inputSchema.properties?.["query"]?.description).toBeDefined();
|
|
96
154
|
});
|
|
97
155
|
|
|
98
|
-
it("
|
|
99
|
-
const request
|
|
156
|
+
it("calls assistantUIDocs", async () => {
|
|
157
|
+
const request = CallToolRequestSchema.parse({
|
|
100
158
|
method: "tools/call",
|
|
101
159
|
params: {
|
|
102
160
|
name: "assistantUIDocs",
|
|
@@ -104,48 +162,55 @@ describe("MCP Protocol Integration", () => {
|
|
|
104
162
|
paths: ["/"],
|
|
105
163
|
},
|
|
106
164
|
},
|
|
107
|
-
};
|
|
108
|
-
|
|
109
|
-
// Parse and validate the request
|
|
110
|
-
const parsed = CallToolRequestSchema.parse(request);
|
|
111
|
-
expect(parsed).toBeDefined();
|
|
165
|
+
});
|
|
166
|
+
const result = await client.request<ToolCallResult>(request);
|
|
112
167
|
|
|
113
|
-
|
|
114
|
-
const handlers = (server as any).server._requestHandlers;
|
|
115
|
-
expect(handlers.get("tools/call")).toBeDefined();
|
|
116
|
-
|
|
117
|
-
// Call the handler through the MCP protocol layer
|
|
118
|
-
const handler = handlers.get("tools/call");
|
|
119
|
-
const result = await handler(parsed, {});
|
|
120
|
-
|
|
121
|
-
expect(result).toBeDefined();
|
|
122
|
-
expect(result.content).toBeDefined();
|
|
123
|
-
expect(result.content[0].type).toBe("text");
|
|
168
|
+
expect(result.content[0]?.type).toBe("text");
|
|
124
169
|
});
|
|
125
170
|
|
|
126
|
-
it("
|
|
127
|
-
const request
|
|
171
|
+
it("calls assistantUIExamples without arguments", async () => {
|
|
172
|
+
const request = CallToolRequestSchema.parse({
|
|
128
173
|
method: "tools/call",
|
|
129
174
|
params: {
|
|
130
175
|
name: "assistantUIExamples",
|
|
131
176
|
arguments: {},
|
|
132
177
|
},
|
|
133
|
-
};
|
|
178
|
+
});
|
|
179
|
+
const result = await client.request<ToolCallResult>(request);
|
|
134
180
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
expect(parsed).toBeDefined();
|
|
181
|
+
expect(result.content[0]?.type).toBe("text");
|
|
182
|
+
});
|
|
138
183
|
|
|
139
|
-
|
|
140
|
-
const
|
|
141
|
-
|
|
184
|
+
it("lists prompts", async () => {
|
|
185
|
+
const request = ListPromptsRequestSchema.parse({
|
|
186
|
+
method: "prompts/list",
|
|
187
|
+
params: {},
|
|
188
|
+
});
|
|
189
|
+
const result = await client.request<PromptListResult>(request);
|
|
190
|
+
const prompt = result.prompts.find(
|
|
191
|
+
(candidate) => candidate.name === "assistant-ui-template-workflow",
|
|
192
|
+
);
|
|
142
193
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
194
|
+
expect(prompt).toMatchObject({
|
|
195
|
+
title: "assistant-ui Template Workflow",
|
|
196
|
+
});
|
|
197
|
+
});
|
|
146
198
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
199
|
+
it("gets the assistant-ui-template-workflow prompt", async () => {
|
|
200
|
+
const request = GetPromptRequestSchema.parse({
|
|
201
|
+
method: "prompts/get",
|
|
202
|
+
params: {
|
|
203
|
+
name: "assistant-ui-template-workflow",
|
|
204
|
+
arguments: {},
|
|
205
|
+
},
|
|
206
|
+
});
|
|
207
|
+
const result = await client.request<PromptGetResult>(request);
|
|
208
|
+
const text = result.messages[0]?.content.text;
|
|
209
|
+
|
|
210
|
+
expect(result.messages).toHaveLength(1);
|
|
211
|
+
expect(result.messages[0]?.content.type).toBe("text");
|
|
212
|
+
expect(text).toContain("assistantUITemplates");
|
|
213
|
+
expect(text).toContain("assistantUITemplateDetails");
|
|
214
|
+
expect(text).toContain("assistantUITemplatePreview");
|
|
150
215
|
});
|
|
151
216
|
});
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import {
|
|
2
|
+
InMemoryTransport,
|
|
3
|
+
type McpServer,
|
|
4
|
+
} from "@modelcontextprotocol/server";
|
|
5
|
+
|
|
6
|
+
type RawMcpRequest = {
|
|
7
|
+
method: string;
|
|
8
|
+
params?: unknown;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
type JsonRpcResponse = {
|
|
12
|
+
id: number;
|
|
13
|
+
result?: unknown;
|
|
14
|
+
error?: {
|
|
15
|
+
code: number;
|
|
16
|
+
message: string;
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
type PendingRequest = {
|
|
21
|
+
resolve: (result: unknown) => void;
|
|
22
|
+
reject: (error: Error) => void;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export type McpTestClient = {
|
|
26
|
+
initialize: () => Promise<unknown>;
|
|
27
|
+
request: <Result>(request: RawMcpRequest) => Promise<Result>;
|
|
28
|
+
close: () => Promise<void>;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
function isJsonRpcResponse(message: unknown): message is JsonRpcResponse {
|
|
32
|
+
return (
|
|
33
|
+
typeof message === "object" &&
|
|
34
|
+
message !== null &&
|
|
35
|
+
"id" in message &&
|
|
36
|
+
typeof message.id === "number" &&
|
|
37
|
+
("result" in message || "error" in message)
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export async function createMcpTestClient(
|
|
42
|
+
server: McpServer,
|
|
43
|
+
): Promise<McpTestClient> {
|
|
44
|
+
const [clientTransport, serverTransport] =
|
|
45
|
+
InMemoryTransport.createLinkedPair();
|
|
46
|
+
const pendingRequests = new Map<number, PendingRequest>();
|
|
47
|
+
let nextRequestId = 1;
|
|
48
|
+
|
|
49
|
+
clientTransport.onmessage = (message) => {
|
|
50
|
+
if (!isJsonRpcResponse(message)) return;
|
|
51
|
+
|
|
52
|
+
const pendingRequest = pendingRequests.get(message.id);
|
|
53
|
+
if (!pendingRequest) return;
|
|
54
|
+
|
|
55
|
+
pendingRequests.delete(message.id);
|
|
56
|
+
if (message.error) {
|
|
57
|
+
pendingRequest.reject(
|
|
58
|
+
new Error(
|
|
59
|
+
`MCP request failed (${message.error.code}): ${message.error.message}`,
|
|
60
|
+
),
|
|
61
|
+
);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
pendingRequest.resolve(message.result);
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
await clientTransport.start();
|
|
69
|
+
await server.connect(serverTransport);
|
|
70
|
+
|
|
71
|
+
const request = <Result>(rawRequest: RawMcpRequest): Promise<Result> => {
|
|
72
|
+
const id = nextRequestId++;
|
|
73
|
+
|
|
74
|
+
return new Promise((resolve, reject) => {
|
|
75
|
+
pendingRequests.set(id, { resolve, reject });
|
|
76
|
+
void clientTransport
|
|
77
|
+
.send({ jsonrpc: "2.0", id, ...rawRequest })
|
|
78
|
+
.catch((error: unknown) => {
|
|
79
|
+
pendingRequests.delete(id);
|
|
80
|
+
reject(error instanceof Error ? error : new Error(String(error)));
|
|
81
|
+
});
|
|
82
|
+
}) as Promise<Result>;
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
return {
|
|
86
|
+
initialize: async () => {
|
|
87
|
+
const result = await request({
|
|
88
|
+
method: "initialize",
|
|
89
|
+
params: {
|
|
90
|
+
protocolVersion: "2025-11-25",
|
|
91
|
+
capabilities: {},
|
|
92
|
+
clientInfo: {
|
|
93
|
+
name: "mcp-docs-server-tests",
|
|
94
|
+
version: "1.0.0",
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
await clientTransport.send({
|
|
100
|
+
jsonrpc: "2.0",
|
|
101
|
+
method: "notifications/initialized",
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
return result;
|
|
105
|
+
},
|
|
106
|
+
request,
|
|
107
|
+
close: async () => {
|
|
108
|
+
await clientTransport.close();
|
|
109
|
+
},
|
|
110
|
+
};
|
|
111
|
+
}
|
|
@@ -1,102 +1,133 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
2
2
|
import { server } from "../../index.js";
|
|
3
|
+
import { createMcpTestClient, type McpTestClient } from "./mcp-test-client.js";
|
|
3
4
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
type Resource = {
|
|
6
|
+
uri: string;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
type ResourceListResult = {
|
|
10
|
+
resources: Resource[];
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
type ResourceReadResult = {
|
|
14
|
+
contents: Array<{
|
|
15
|
+
mimeType?: string;
|
|
16
|
+
text?: string;
|
|
17
|
+
}>;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
function requireResource(resources: Resource[], prefix: string): Resource {
|
|
21
|
+
const resource = resources.find((candidate) =>
|
|
22
|
+
candidate.uri.startsWith(prefix),
|
|
23
|
+
);
|
|
24
|
+
expect(resource).toBeDefined();
|
|
25
|
+
if (!resource) throw new Error(`Missing resource with URI prefix: ${prefix}`);
|
|
26
|
+
return resource;
|
|
9
27
|
}
|
|
10
28
|
|
|
11
29
|
describe("MCP resources", () => {
|
|
30
|
+
let client: McpTestClient;
|
|
31
|
+
|
|
32
|
+
beforeEach(async () => {
|
|
33
|
+
client = await createMcpTestClient(server);
|
|
34
|
+
await client.initialize();
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
afterEach(async () => {
|
|
38
|
+
await client?.close();
|
|
39
|
+
});
|
|
40
|
+
|
|
12
41
|
it("lists docs and example resources", async () => {
|
|
13
|
-
const result = await
|
|
14
|
-
|
|
15
|
-
{},
|
|
16
|
-
);
|
|
42
|
+
const result = await client.request<ResourceListResult>({
|
|
43
|
+
method: "resources/list",
|
|
44
|
+
params: {},
|
|
45
|
+
});
|
|
46
|
+
|
|
17
47
|
expect(result.resources.length).toBeGreaterThan(0);
|
|
18
48
|
expect(
|
|
19
|
-
result.resources.some((
|
|
49
|
+
result.resources.some((resource) =>
|
|
50
|
+
resource.uri.startsWith("aui-docs:///"),
|
|
51
|
+
),
|
|
20
52
|
).toBe(true);
|
|
21
53
|
expect(
|
|
22
|
-
result.resources.some((
|
|
54
|
+
result.resources.some((resource) =>
|
|
55
|
+
resource.uri.startsWith("aui-example:///"),
|
|
56
|
+
),
|
|
23
57
|
).toBe(true);
|
|
24
58
|
});
|
|
25
59
|
|
|
26
60
|
it("reads a documentation resource as markdown", async () => {
|
|
27
|
-
const list = await
|
|
28
|
-
|
|
29
|
-
{},
|
|
30
|
-
);
|
|
31
|
-
const doc = list.resources
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
);
|
|
38
|
-
expect(read.contents[0]
|
|
39
|
-
expect(
|
|
40
|
-
expect(read.contents[0].text.length).toBeGreaterThan(0);
|
|
61
|
+
const list = await client.request<ResourceListResult>({
|
|
62
|
+
method: "resources/list",
|
|
63
|
+
params: {},
|
|
64
|
+
});
|
|
65
|
+
const doc = requireResource(list.resources, "aui-docs:///");
|
|
66
|
+
const read = await client.request<ResourceReadResult>({
|
|
67
|
+
method: "resources/read",
|
|
68
|
+
params: { uri: doc.uri },
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
expect(read.contents[0]?.mimeType).toBe("text/markdown");
|
|
72
|
+
expect(typeof read.contents[0]?.text).toBe("string");
|
|
73
|
+
expect(read.contents[0]?.text.length).toBeGreaterThan(0);
|
|
41
74
|
});
|
|
42
75
|
|
|
43
76
|
it("reads a slash-containing documentation resource", async () => {
|
|
44
|
-
const list = await
|
|
45
|
-
|
|
46
|
-
{},
|
|
47
|
-
);
|
|
77
|
+
const list = await client.request<ResourceListResult>({
|
|
78
|
+
method: "resources/list",
|
|
79
|
+
params: {},
|
|
80
|
+
});
|
|
48
81
|
const prefix = "aui-docs:///";
|
|
49
82
|
const nested = list.resources.find(
|
|
50
|
-
(
|
|
51
|
-
|
|
83
|
+
(resource) =>
|
|
84
|
+
resource.uri.startsWith(prefix) &&
|
|
85
|
+
resource.uri.slice(prefix.length).includes("/"),
|
|
52
86
|
);
|
|
87
|
+
|
|
53
88
|
expect(nested).toBeDefined();
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
89
|
+
if (!nested) throw new Error("Missing nested documentation resource");
|
|
90
|
+
|
|
91
|
+
const read = await client.request<ResourceReadResult>({
|
|
92
|
+
method: "resources/read",
|
|
93
|
+
params: { uri: nested.uri },
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
expect(read.contents[0]?.mimeType).toBe("text/markdown");
|
|
97
|
+
expect(read.contents[0]?.text.length).toBeGreaterThan(0);
|
|
60
98
|
});
|
|
61
99
|
|
|
62
100
|
it("errors on an unknown documentation resource", async () => {
|
|
63
101
|
await expect(
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
},
|
|
69
|
-
{},
|
|
70
|
-
),
|
|
102
|
+
client.request({
|
|
103
|
+
method: "resources/read",
|
|
104
|
+
params: { uri: "aui-docs:///definitely-not-a-real-doc" },
|
|
105
|
+
}),
|
|
71
106
|
).rejects.toThrow();
|
|
72
107
|
});
|
|
73
108
|
|
|
74
109
|
it("reads an example resource as markdown", async () => {
|
|
75
|
-
const list = await
|
|
76
|
-
|
|
77
|
-
{},
|
|
78
|
-
);
|
|
79
|
-
const example = list.resources
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
);
|
|
86
|
-
expect(read.contents[0]
|
|
87
|
-
expect(
|
|
88
|
-
expect(read.contents[0].text.length).toBeGreaterThan(0);
|
|
110
|
+
const list = await client.request<ResourceListResult>({
|
|
111
|
+
method: "resources/list",
|
|
112
|
+
params: {},
|
|
113
|
+
});
|
|
114
|
+
const example = requireResource(list.resources, "aui-example:///");
|
|
115
|
+
const read = await client.request<ResourceReadResult>({
|
|
116
|
+
method: "resources/read",
|
|
117
|
+
params: { uri: example.uri },
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
expect(read.contents[0]?.mimeType).toBe("text/markdown");
|
|
121
|
+
expect(typeof read.contents[0]?.text).toBe("string");
|
|
122
|
+
expect(read.contents[0]?.text.length).toBeGreaterThan(0);
|
|
89
123
|
});
|
|
90
124
|
|
|
91
125
|
it("errors on an unknown example resource", async () => {
|
|
92
126
|
await expect(
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
},
|
|
98
|
-
{},
|
|
99
|
-
),
|
|
127
|
+
client.request({
|
|
128
|
+
method: "resources/read",
|
|
129
|
+
params: { uri: "aui-example:///definitely-not-a-real-example" },
|
|
130
|
+
}),
|
|
100
131
|
).rejects.toThrow();
|
|
101
132
|
});
|
|
102
133
|
});
|
|
@@ -5,11 +5,19 @@ import { PACKAGE_DIR } from "../../constants.js";
|
|
|
5
5
|
import { docsTools } from "../docs.js";
|
|
6
6
|
import { examplesTools } from "../examples.js";
|
|
7
7
|
import { searchTools } from "../search.js";
|
|
8
|
+
import {
|
|
9
|
+
xuluxTemplatesListTool,
|
|
10
|
+
xuluxTemplateDetailsTool,
|
|
11
|
+
xuluxTemplatePreviewTool,
|
|
12
|
+
} from "../xulux-templates.js";
|
|
8
13
|
|
|
9
14
|
const tools = {
|
|
10
15
|
assistantUIDocs: docsTools,
|
|
11
16
|
assistantUIExamples: examplesTools,
|
|
12
17
|
assistantUISearch: searchTools,
|
|
18
|
+
assistantUITemplates: xuluxTemplatesListTool,
|
|
19
|
+
assistantUITemplateDetails: xuluxTemplateDetailsTool,
|
|
20
|
+
assistantUITemplatePreview: xuluxTemplatePreviewTool,
|
|
13
21
|
};
|
|
14
22
|
|
|
15
23
|
export const testContext = {
|