@lglab/compose-ui-mcp 0.1.1 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +215 -8
- package/dist/index.js.map +1 -1
- package/dist/llms-full.txt +18 -0
- package/dist/llms.txt +18 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -4,9 +4,10 @@ import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mc
|
|
|
4
4
|
import { readFile, readdir } from "node:fs/promises";
|
|
5
5
|
import { dirname, resolve } from "node:path";
|
|
6
6
|
import { fileURLToPath } from "node:url";
|
|
7
|
+
import { z } from "zod";
|
|
7
8
|
|
|
8
|
-
//#region src/
|
|
9
|
-
const LLMS_DIR = resolve(dirname(fileURLToPath(import.meta.url)), "
|
|
9
|
+
//#region src/lib/component-data.ts
|
|
10
|
+
const LLMS_DIR = resolve(dirname(fileURLToPath(import.meta.url)), "llms");
|
|
10
11
|
function slugToName(slug) {
|
|
11
12
|
return slug.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
12
13
|
}
|
|
@@ -57,6 +58,9 @@ async function getComponentsList() {
|
|
|
57
58
|
return [];
|
|
58
59
|
}
|
|
59
60
|
}
|
|
61
|
+
|
|
62
|
+
//#endregion
|
|
63
|
+
//#region src/resources/components.ts
|
|
60
64
|
function registerComponentsResource(server) {
|
|
61
65
|
server.registerResource("components", "compose-ui://components", {
|
|
62
66
|
title: "Compose UI Components",
|
|
@@ -97,12 +101,19 @@ A React component library built on Base UI primitives with Tailwind CSS v4 styli
|
|
|
97
101
|
- Tailwind CSS for styling
|
|
98
102
|
- TypeScript-first
|
|
99
103
|
|
|
100
|
-
##
|
|
104
|
+
## Available Tools
|
|
105
|
+
|
|
106
|
+
Use these tools to access component documentation:
|
|
101
107
|
|
|
102
|
-
|
|
108
|
+
- **find_components**: Fuzzy search all components by name
|
|
109
|
+
- **get_component**: Get full documentation for a specific component (supports section filtering)
|
|
103
110
|
|
|
104
|
-
|
|
105
|
-
|
|
111
|
+
## Styling Guidelines
|
|
112
|
+
|
|
113
|
+
- Components are **pre-styled and ready to use** - do not add custom CSS, Tailwind classes, or inline styles
|
|
114
|
+
- Only add custom styling if the user explicitly requests it
|
|
115
|
+
- Use built-in variant props (e.g., \`variant="outline"\`, \`size="sm"\`) for different appearances
|
|
116
|
+
- Use specific import paths: \`import { Button } from '@lglab/compose-ui/button'\`
|
|
106
117
|
`;
|
|
107
118
|
function registerOverviewResource(server) {
|
|
108
119
|
server.registerResource("overview", "compose-ui://overview", {
|
|
@@ -124,9 +135,205 @@ function registerResources(server) {
|
|
|
124
135
|
registerComponentDocResource(server);
|
|
125
136
|
}
|
|
126
137
|
|
|
138
|
+
//#endregion
|
|
139
|
+
//#region src/lib/fuzzy-match.ts
|
|
140
|
+
/**
|
|
141
|
+
* Calculate a fuzzy match score between a query and a target string.
|
|
142
|
+
* Returns a score from 0 to 1, where 1 is a perfect match.
|
|
143
|
+
*/
|
|
144
|
+
function fuzzyScore(query, target) {
|
|
145
|
+
const q = query.toLowerCase();
|
|
146
|
+
const t = target.toLowerCase();
|
|
147
|
+
if (q === t) return 1;
|
|
148
|
+
if (t.startsWith(q)) return .9;
|
|
149
|
+
if (t.includes(q)) return .7;
|
|
150
|
+
let queryIndex = 0;
|
|
151
|
+
let matchCount = 0;
|
|
152
|
+
for (const char of t) if (queryIndex < q.length && char === q[queryIndex]) {
|
|
153
|
+
matchCount++;
|
|
154
|
+
queryIndex++;
|
|
155
|
+
}
|
|
156
|
+
if (queryIndex === q.length) return .3 + matchCount / t.length * .3;
|
|
157
|
+
return new Set([...q].filter((c) => t.includes(c))).size / Math.max(q.length, t.length) * .3;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Search items using fuzzy matching.
|
|
161
|
+
* Returns items sorted by match score (highest first).
|
|
162
|
+
*/
|
|
163
|
+
function fuzzySearch(query, items, getSearchableText, minScore = .1) {
|
|
164
|
+
const results = [];
|
|
165
|
+
for (const item of items) {
|
|
166
|
+
const score = fuzzyScore(query, getSearchableText(item));
|
|
167
|
+
if (score >= minScore) results.push({
|
|
168
|
+
item,
|
|
169
|
+
score
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
results.sort((a, b) => b.score - a.score);
|
|
173
|
+
return results;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
//#endregion
|
|
177
|
+
//#region src/tools/find-components.ts
|
|
178
|
+
const inputSchema$1 = {
|
|
179
|
+
query: z.string().optional().describe("Fuzzy search query. Omit to list all components."),
|
|
180
|
+
limit: z.number().min(1).max(100).default(50).describe("Maximum number of results to return (default: 50)")
|
|
181
|
+
};
|
|
182
|
+
function registerFindComponentsTool(server) {
|
|
183
|
+
server.registerTool("find_components", {
|
|
184
|
+
description: "Find Compose UI components. Call without query to list all, or with query for fuzzy search.",
|
|
185
|
+
inputSchema: inputSchema$1
|
|
186
|
+
}, async ({ query, limit }) => {
|
|
187
|
+
const allComponents = await getComponentsList();
|
|
188
|
+
let components;
|
|
189
|
+
if (query) components = fuzzySearch(query, allComponents, (c) => `${c.name} ${c.slug}`).slice(0, limit ?? 50).map((r) => ({
|
|
190
|
+
slug: r.item.slug,
|
|
191
|
+
name: r.item.name,
|
|
192
|
+
description: r.item.description
|
|
193
|
+
}));
|
|
194
|
+
else components = allComponents.slice(0, limit ?? 50).map((c) => ({
|
|
195
|
+
slug: c.slug,
|
|
196
|
+
name: c.name,
|
|
197
|
+
description: c.description
|
|
198
|
+
}));
|
|
199
|
+
const result = {
|
|
200
|
+
count: components.length,
|
|
201
|
+
components
|
|
202
|
+
};
|
|
203
|
+
return { content: [{
|
|
204
|
+
type: "text",
|
|
205
|
+
text: JSON.stringify(result, null, 2)
|
|
206
|
+
}] };
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
//#endregion
|
|
211
|
+
//#region src/lib/markdown-parser.ts
|
|
212
|
+
const SECTION_MAPPINGS = {
|
|
213
|
+
installation: "installation",
|
|
214
|
+
import: "import",
|
|
215
|
+
examples: "examples",
|
|
216
|
+
resources: "resources"
|
|
217
|
+
};
|
|
218
|
+
/**
|
|
219
|
+
* Parse markdown content into sections based on ## headings.
|
|
220
|
+
*/
|
|
221
|
+
function parseMarkdownSections(markdown) {
|
|
222
|
+
const lines = markdown.split("\n");
|
|
223
|
+
const sections = [];
|
|
224
|
+
let title = "";
|
|
225
|
+
const overviewLines = [];
|
|
226
|
+
let currentSection = null;
|
|
227
|
+
const rawSections = [];
|
|
228
|
+
for (const line of lines) {
|
|
229
|
+
if (line.startsWith("# ") && !title) {
|
|
230
|
+
title = line.slice(2).trim();
|
|
231
|
+
continue;
|
|
232
|
+
}
|
|
233
|
+
if (line.startsWith("## ")) {
|
|
234
|
+
if (currentSection) rawSections.push(currentSection);
|
|
235
|
+
else if (overviewLines.length > 0) sections.push({
|
|
236
|
+
type: "overview",
|
|
237
|
+
title: title || "Overview",
|
|
238
|
+
content: `# ${title}\n\n${overviewLines.join("\n").trim()}`
|
|
239
|
+
});
|
|
240
|
+
currentSection = {
|
|
241
|
+
heading: line.slice(3).trim(),
|
|
242
|
+
content: ""
|
|
243
|
+
};
|
|
244
|
+
continue;
|
|
245
|
+
}
|
|
246
|
+
if (currentSection) currentSection.content += line + "\n";
|
|
247
|
+
else if (title) overviewLines.push(line);
|
|
248
|
+
}
|
|
249
|
+
if (currentSection) rawSections.push(currentSection);
|
|
250
|
+
else if (overviewLines.length > 0 && sections.length === 0) sections.push({
|
|
251
|
+
type: "overview",
|
|
252
|
+
title: title || "Overview",
|
|
253
|
+
content: `# ${title}\n\n${overviewLines.join("\n").trim()}`
|
|
254
|
+
});
|
|
255
|
+
for (const raw of rawSections) {
|
|
256
|
+
const sectionType = SECTION_MAPPINGS[raw.heading.toLowerCase()] || "overview";
|
|
257
|
+
sections.push({
|
|
258
|
+
type: sectionType,
|
|
259
|
+
title: raw.heading,
|
|
260
|
+
content: `## ${raw.heading}\n${raw.content.trim()}`
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
return sections;
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Extract specific sections from markdown content.
|
|
267
|
+
* If no sections are specified, returns the full content.
|
|
268
|
+
*/
|
|
269
|
+
function extractSections(markdown, sectionTypes) {
|
|
270
|
+
if (!sectionTypes || sectionTypes.length === 0) return markdown;
|
|
271
|
+
const filtered = parseMarkdownSections(markdown).filter((s) => sectionTypes.includes(s.type));
|
|
272
|
+
if (filtered.length === 0) return "";
|
|
273
|
+
const includesOverview = sectionTypes.includes("overview");
|
|
274
|
+
const overviewSection = filtered.find((s) => s.type === "overview");
|
|
275
|
+
if (includesOverview && overviewSection) {
|
|
276
|
+
const otherSections = filtered.filter((s) => s.type !== "overview");
|
|
277
|
+
return [overviewSection.content, ...otherSections.map((s) => s.content)].join("\n\n");
|
|
278
|
+
}
|
|
279
|
+
return filtered.map((s) => s.content).join("\n\n");
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
//#endregion
|
|
283
|
+
//#region src/tools/get-component.ts
|
|
284
|
+
const inputSchema = {
|
|
285
|
+
slug: z.string().describe("Component slug (e.g., \"button\", \"alert-dialog\")"),
|
|
286
|
+
sections: z.array(z.enum([
|
|
287
|
+
"overview",
|
|
288
|
+
"installation",
|
|
289
|
+
"import",
|
|
290
|
+
"examples",
|
|
291
|
+
"resources"
|
|
292
|
+
])).optional().describe("Filter sections: \"overview\", \"installation\", \"import\", \"examples\", \"resources\". Default: all.")
|
|
293
|
+
};
|
|
294
|
+
function registerGetComponentTool(server) {
|
|
295
|
+
server.registerTool("get_component", {
|
|
296
|
+
description: "Get documentation for a Compose UI component. Supports fuzzy matching if exact slug not found.",
|
|
297
|
+
inputSchema
|
|
298
|
+
}, async ({ slug, sections }) => {
|
|
299
|
+
const content = await getComponentContent(slug);
|
|
300
|
+
if (content) {
|
|
301
|
+
const filteredContent = extractSections(content, sections);
|
|
302
|
+
const result = {
|
|
303
|
+
slug,
|
|
304
|
+
name: slugToName(slug),
|
|
305
|
+
found: true,
|
|
306
|
+
content: filteredContent || content
|
|
307
|
+
};
|
|
308
|
+
return { content: [{
|
|
309
|
+
type: "text",
|
|
310
|
+
text: JSON.stringify(result, null, 2)
|
|
311
|
+
}] };
|
|
312
|
+
}
|
|
313
|
+
const suggestions = fuzzySearch(slug, await getComponentsList(), (c) => c.slug, .2).slice(0, 5).map((r) => ({
|
|
314
|
+
slug: r.item.slug,
|
|
315
|
+
name: r.item.name,
|
|
316
|
+
score: Math.round(r.score * 100) / 100
|
|
317
|
+
}));
|
|
318
|
+
const result = {
|
|
319
|
+
slug,
|
|
320
|
+
found: false,
|
|
321
|
+
suggestions,
|
|
322
|
+
message: `Component '${slug}' not found. ${suggestions.length > 0 ? `Did you mean '${suggestions[0].slug}'?` : "No similar components found."}`
|
|
323
|
+
};
|
|
324
|
+
return { content: [{
|
|
325
|
+
type: "text",
|
|
326
|
+
text: JSON.stringify(result, null, 2)
|
|
327
|
+
}] };
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
|
|
127
331
|
//#endregion
|
|
128
332
|
//#region src/tools/index.ts
|
|
129
|
-
function registerTools(server) {
|
|
333
|
+
function registerTools(server) {
|
|
334
|
+
registerFindComponentsTool(server);
|
|
335
|
+
registerGetComponentTool(server);
|
|
336
|
+
}
|
|
130
337
|
|
|
131
338
|
//#endregion
|
|
132
339
|
//#region src/server.ts
|
|
@@ -136,7 +343,7 @@ function createServer() {
|
|
|
136
343
|
version: "0.1.0"
|
|
137
344
|
});
|
|
138
345
|
registerResources(server);
|
|
139
|
-
|
|
346
|
+
registerTools(server);
|
|
140
347
|
return server;
|
|
141
348
|
}
|
|
142
349
|
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/resources/components.ts","../src/resources/overview.ts","../src/resources/index.ts","../src/tools/index.ts","../src/server.ts","../src/index.ts"],"sourcesContent":["import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport { ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport { readFile, readdir } from 'node:fs/promises'\nimport { dirname, resolve } from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nconst __dirname = dirname(fileURLToPath(import.meta.url))\nconst LLMS_DIR = resolve(__dirname, 'assets/llms')\n\ninterface ComponentInfo {\n name: string\n slug: string\n description: string\n documentationUri: string\n}\n\nfunction slugToName(slug: string): string {\n return slug\n .split('-')\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1))\n .join(' ')\n}\n\nfunction parseMarkdownFile(content: string, slug: string): ComponentInfo {\n const lines = content.split('\\n')\n\n // Extract title from first # heading\n let name = slugToName(slug)\n for (const line of lines) {\n if (line.startsWith('# ')) {\n name = line.slice(2).trim()\n break\n }\n }\n\n // Extract description (first non-empty line after the heading)\n let description = ''\n let foundHeading = false\n for (const line of lines) {\n if (line.startsWith('# ')) {\n foundHeading = true\n continue\n }\n if (foundHeading && line.trim() !== '') {\n description = line.trim()\n break\n }\n }\n\n return {\n name,\n slug,\n description,\n documentationUri: `compose-ui://components/${slug}`,\n }\n}\n\nasync function getComponentContent(slug: string): Promise<string | null> {\n try {\n const filePath = resolve(LLMS_DIR, `${slug}.md`)\n return await readFile(filePath, 'utf-8')\n } catch {\n return null\n }\n}\n\nasync function getComponentsList(): Promise<ComponentInfo[]> {\n try {\n const files = await readdir(LLMS_DIR)\n const mdFiles = files.filter((f) => f.endsWith('.md')).sort()\n\n const components: ComponentInfo[] = []\n\n for (const file of mdFiles) {\n const slug = file.replace('.md', '')\n const content = await readFile(resolve(LLMS_DIR, file), 'utf-8')\n components.push(parseMarkdownFile(content, slug))\n }\n\n return components\n } catch {\n return []\n }\n}\n\nexport function registerComponentsResource(server: McpServer): void {\n server.registerResource(\n 'components',\n 'compose-ui://components',\n {\n title: 'Compose UI Components',\n description: 'List of all Compose UI components with metadata',\n mimeType: 'application/json',\n },\n async () => ({\n contents: [\n {\n uri: 'compose-ui://components',\n mimeType: 'application/json',\n text: JSON.stringify(await getComponentsList(), null, 2),\n },\n ],\n }),\n )\n}\n\nexport function registerComponentDocResource(server: McpServer): void {\n server.registerResource(\n 'component-doc',\n new ResourceTemplate('compose-ui://components/{slug}', { list: undefined }),\n {\n title: 'Component Documentation',\n description: 'Full markdown documentation for a Compose UI component',\n mimeType: 'text/markdown',\n },\n async (uri, variables) => {\n const slug = variables.slug as string\n const content = await getComponentContent(slug)\n if (!content) {\n throw new Error(`Component not found: ${slug}`)\n }\n return {\n contents: [\n {\n uri: uri.href,\n mimeType: 'text/markdown',\n text: content,\n },\n ],\n }\n },\n )\n}\n","import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\n\nconst text = `# Compose UI\n\nA React component library built on Base UI primitives with Tailwind CSS v4 styling.\n\n## Key Principles\n- Composition over configuration\n- Base UI handles accessibility and behavior\n- Tailwind CSS for styling\n- TypeScript-first\n\n## Using This MCP Server\n\nTo work with Compose UI components, use the available tools:\n\n- \\`compose-ui://components\\`: List of available components\n- \\`compose-ui://components/{slug}\\`: Documentation for a specific component\n`\n\nexport function registerOverviewResource(server: McpServer): void {\n server.registerResource(\n 'overview',\n 'compose-ui://overview',\n {\n title: 'Compose UI Overview',\n description: 'Compose UI overview documentation',\n mimeType: 'text/plain',\n },\n async () => ({\n contents: [\n {\n uri: 'compose-ui://overview',\n mimeType: 'text/markdown',\n text,\n },\n ],\n }),\n )\n}\n","import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\n\nimport { registerComponentDocResource, registerComponentsResource } from './components.js'\nimport { registerOverviewResource } from './overview.js'\n\nexport function registerResources(server: McpServer): void {\n registerOverviewResource(server)\n registerComponentsResource(server)\n registerComponentDocResource(server)\n}\n","import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\n\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nexport function registerTools(server: McpServer): void {\n // Tools will be registered here\n // Example: registerSearchTool(server)\n}\n","import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\n\nimport { registerResources } from './resources/index.js'\nimport { registerTools } from './tools/index.js'\n\nexport function createServer(): McpServer {\n const server = new McpServer({\n name: 'compose-ui-mcp',\n version: '0.1.0',\n })\n\n registerResources(server)\n registerTools(server)\n\n return server\n}\n","#!/usr/bin/env node\n\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'\n\nimport { createServer } from './server.js'\n\nasync function main() {\n const server = createServer()\n const transport = new StdioServerTransport()\n\n await server.connect(transport)\n\n process.on('SIGINT', async () => {\n await server.close()\n process.exit(0)\n })\n}\n\nmain().catch((error) => {\n console.error('Server error:', error) // eslint-disable-line no-console\n process.exit(1)\n})\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["inputSchema"],"sources":["../src/lib/component-data.ts","../src/resources/components.ts","../src/resources/overview.ts","../src/resources/index.ts","../src/lib/fuzzy-match.ts","../src/tools/find-components.ts","../src/lib/markdown-parser.ts","../src/tools/get-component.ts","../src/tools/index.ts","../src/server.ts","../src/index.ts"],"sourcesContent":["import { readFile, readdir } from 'node:fs/promises'\nimport { dirname, resolve } from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nconst __dirname = dirname(fileURLToPath(import.meta.url))\n// After build, assets are copied to dist/ alongside index.js\n// In dev, we're in src/lib/ and assets are at ../../assets/llms\n// At runtime (from dist/index.js), llms is at ./llms\nconst LLMS_DIR = resolve(__dirname, 'llms')\n\nexport interface ComponentInfo {\n name: string\n slug: string\n description: string\n documentationUri: string\n}\n\nexport function slugToName(slug: string): string {\n return slug\n .split('-')\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1))\n .join(' ')\n}\n\nfunction parseMarkdownFile(content: string, slug: string): ComponentInfo {\n const lines = content.split('\\n')\n\n // Extract title from first # heading\n let name = slugToName(slug)\n for (const line of lines) {\n if (line.startsWith('# ')) {\n name = line.slice(2).trim()\n break\n }\n }\n\n // Extract description (first non-empty line after the heading)\n let description = ''\n let foundHeading = false\n for (const line of lines) {\n if (line.startsWith('# ')) {\n foundHeading = true\n continue\n }\n if (foundHeading && line.trim() !== '') {\n description = line.trim()\n break\n }\n }\n\n return {\n name,\n slug,\n description,\n documentationUri: `compose-ui://components/${slug}`,\n }\n}\n\nexport async function getComponentContent(slug: string): Promise<string | null> {\n try {\n const filePath = resolve(LLMS_DIR, `${slug}.md`)\n return await readFile(filePath, 'utf-8')\n } catch {\n return null\n }\n}\n\nexport async function getComponentsList(): Promise<ComponentInfo[]> {\n try {\n const files = await readdir(LLMS_DIR)\n const mdFiles = files.filter((f) => f.endsWith('.md')).sort()\n\n const components: ComponentInfo[] = []\n\n for (const file of mdFiles) {\n const slug = file.replace('.md', '')\n const content = await readFile(resolve(LLMS_DIR, file), 'utf-8')\n components.push(parseMarkdownFile(content, slug))\n }\n\n return components\n } catch {\n return []\n }\n}\n","import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport { ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js'\n\nimport { getComponentContent, getComponentsList } from '../lib/component-data.js'\n\nexport function registerComponentsResource(server: McpServer): void {\n server.registerResource(\n 'components',\n 'compose-ui://components',\n {\n title: 'Compose UI Components',\n description: 'List of all Compose UI components with metadata',\n mimeType: 'application/json',\n },\n async () => ({\n contents: [\n {\n uri: 'compose-ui://components',\n mimeType: 'application/json',\n text: JSON.stringify(await getComponentsList(), null, 2),\n },\n ],\n }),\n )\n}\n\nexport function registerComponentDocResource(server: McpServer): void {\n server.registerResource(\n 'component-doc',\n new ResourceTemplate('compose-ui://components/{slug}', { list: undefined }),\n {\n title: 'Component Documentation',\n description: 'Full markdown documentation for a Compose UI component',\n mimeType: 'text/markdown',\n },\n async (uri, variables) => {\n const slug = variables.slug as string\n const content = await getComponentContent(slug)\n if (!content) {\n throw new Error(`Component not found: ${slug}`)\n }\n return {\n contents: [\n {\n uri: uri.href,\n mimeType: 'text/markdown',\n text: content,\n },\n ],\n }\n },\n )\n}\n","import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\n\nconst text = `# Compose UI\n\nA React component library built on Base UI primitives with Tailwind CSS v4 styling.\n\n## Key Principles\n- Composition over configuration\n- Base UI handles accessibility and behavior\n- Tailwind CSS for styling\n- TypeScript-first\n\n## Available Tools\n\nUse these tools to access component documentation:\n\n- **find_components**: Fuzzy search all components by name\n- **get_component**: Get full documentation for a specific component (supports section filtering)\n\n## Styling Guidelines\n\n- Components are **pre-styled and ready to use** - do not add custom CSS, Tailwind classes, or inline styles\n- Only add custom styling if the user explicitly requests it\n- Use built-in variant props (e.g., \\`variant=\"outline\"\\`, \\`size=\"sm\"\\`) for different appearances\n- Use specific import paths: \\`import { Button } from '@lglab/compose-ui/button'\\`\n`\n\nexport function registerOverviewResource(server: McpServer): void {\n server.registerResource(\n 'overview',\n 'compose-ui://overview',\n {\n title: 'Compose UI Overview',\n description: 'Compose UI overview documentation',\n mimeType: 'text/plain',\n },\n async () => ({\n contents: [\n {\n uri: 'compose-ui://overview',\n mimeType: 'text/markdown',\n text,\n },\n ],\n }),\n )\n}\n","import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\n\nimport { registerComponentDocResource, registerComponentsResource } from './components.js'\nimport { registerOverviewResource } from './overview.js'\n\nexport function registerResources(server: McpServer): void {\n registerOverviewResource(server)\n registerComponentsResource(server)\n registerComponentDocResource(server)\n}\n","export interface FuzzyMatchResult<T> {\n item: T\n score: number\n}\n\n/**\n * Calculate a fuzzy match score between a query and a target string.\n * Returns a score from 0 to 1, where 1 is a perfect match.\n */\nexport function fuzzyScore(query: string, target: string): number {\n const q = query.toLowerCase()\n const t = target.toLowerCase()\n\n // Exact match\n if (q === t) return 1.0\n\n // Target starts with query\n if (t.startsWith(q)) return 0.9\n\n // Target contains query as substring\n if (t.includes(q)) return 0.7\n\n // Check if all query characters appear in order\n let queryIndex = 0\n let matchCount = 0\n\n for (const char of t) {\n if (queryIndex < q.length && char === q[queryIndex]) {\n matchCount++\n queryIndex++\n }\n }\n\n // All query characters found in order\n if (queryIndex === q.length) {\n // Score based on how much of the query matched vs target length\n return 0.3 + (matchCount / t.length) * 0.3\n }\n\n // Partial character match - calculate Levenshtein-like similarity\n const commonChars = new Set([...q].filter((c) => t.includes(c)))\n const similarity = commonChars.size / Math.max(q.length, t.length)\n\n return similarity * 0.3\n}\n\n/**\n * Search items using fuzzy matching.\n * Returns items sorted by match score (highest first).\n */\nexport function fuzzySearch<T>(\n query: string,\n items: T[],\n getSearchableText: (item: T) => string,\n minScore = 0.1,\n): FuzzyMatchResult<T>[] {\n const results: FuzzyMatchResult<T>[] = []\n\n for (const item of items) {\n const text = getSearchableText(item)\n const score = fuzzyScore(query, text)\n\n if (score >= minScore) {\n results.push({ item, score })\n }\n }\n\n // Sort by score descending\n results.sort((a, b) => b.score - a.score)\n\n return results\n}\n\n/**\n * Find the best fuzzy match for a query.\n * Returns the best match if score is above minScore, otherwise null.\n */\nexport function findBestMatch<T>(\n query: string,\n items: T[],\n getSearchableText: (item: T) => string,\n minScore = 0.3,\n): FuzzyMatchResult<T> | null {\n const results = fuzzySearch(query, items, getSearchableText, minScore)\n return results.length > 0 ? results[0] : null\n}\n","import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport { z } from 'zod'\n\nimport { getComponentsList } from '../lib/component-data.js'\nimport { fuzzySearch } from '../lib/fuzzy-match.js'\n\nconst inputSchema = {\n query: z\n .string()\n .optional()\n .describe('Fuzzy search query. Omit to list all components.'),\n limit: z\n .number()\n .min(1)\n .max(100)\n .default(50)\n .describe('Maximum number of results to return (default: 50)'),\n}\n\ninterface FindComponentsResult {\n count: number\n components: Array<{\n slug: string\n name: string\n description: string\n }>\n}\n\nexport function registerFindComponentsTool(server: McpServer): void {\n server.registerTool(\n 'find_components',\n {\n description:\n 'Find Compose UI components. Call without query to list all, or with query for fuzzy search.',\n inputSchema,\n },\n async ({ query, limit }) => {\n const allComponents = await getComponentsList()\n\n let components: Array<{ slug: string; name: string; description: string }>\n\n if (query) {\n // Fuzzy search on both name and slug\n const results = fuzzySearch(query, allComponents, (c) => `${c.name} ${c.slug}`)\n\n components = results.slice(0, limit ?? 50).map((r) => ({\n slug: r.item.slug,\n name: r.item.name,\n description: r.item.description,\n }))\n } else {\n // Return all components up to limit\n components = allComponents.slice(0, limit ?? 50).map((c) => ({\n slug: c.slug,\n name: c.name,\n description: c.description,\n }))\n }\n\n const result: FindComponentsResult = {\n count: components.length,\n components,\n }\n\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify(result, null, 2),\n },\n ],\n }\n },\n )\n}\n","export type SectionType =\n | 'overview'\n | 'installation'\n | 'import'\n | 'examples'\n | 'resources'\n\nexport interface ParsedSection {\n type: SectionType\n title: string\n content: string\n}\n\nconst SECTION_MAPPINGS: Record<string, SectionType> = {\n installation: 'installation',\n import: 'import',\n examples: 'examples',\n resources: 'resources',\n}\n\ninterface RawSection {\n heading: string\n content: string\n}\n\n/**\n * Parse markdown content into sections based on ## headings.\n */\nexport function parseMarkdownSections(markdown: string): ParsedSection[] {\n const lines = markdown.split('\\n')\n const sections: ParsedSection[] = []\n\n // Find title and description (overview section)\n let title = ''\n const overviewLines: string[] = []\n let currentSection: RawSection | null = null\n const rawSections: RawSection[] = []\n\n for (const line of lines) {\n // Main title\n if (line.startsWith('# ') && !title) {\n title = line.slice(2).trim()\n continue\n }\n\n // Section heading\n if (line.startsWith('## ')) {\n // Save previous section\n if (currentSection) {\n rawSections.push(currentSection)\n } else if (overviewLines.length > 0) {\n // Save overview content collected before first ## heading\n sections.push({\n type: 'overview',\n title: title || 'Overview',\n content: `# ${title}\\n\\n${overviewLines.join('\\n').trim()}`,\n })\n }\n\n currentSection = {\n heading: line.slice(3).trim(),\n content: '',\n }\n continue\n }\n\n // Content lines\n if (currentSection) {\n currentSection.content += line + '\\n'\n } else if (title) {\n // Content before first ## heading is part of overview\n overviewLines.push(line)\n }\n }\n\n // Save last section\n if (currentSection) {\n rawSections.push(currentSection)\n } else if (overviewLines.length > 0 && sections.length === 0) {\n // No sections found, treat everything as overview\n sections.push({\n type: 'overview',\n title: title || 'Overview',\n content: `# ${title}\\n\\n${overviewLines.join('\\n').trim()}`,\n })\n }\n\n // Convert raw sections to typed sections\n for (const raw of rawSections) {\n const headingLower = raw.heading.toLowerCase()\n const sectionType = SECTION_MAPPINGS[headingLower] || 'overview'\n\n sections.push({\n type: sectionType,\n title: raw.heading,\n content: `## ${raw.heading}\\n${raw.content.trim()}`,\n })\n }\n\n return sections\n}\n\n/**\n * Extract specific sections from markdown content.\n * If no sections are specified, returns the full content.\n */\nexport function extractSections(markdown: string, sectionTypes?: SectionType[]): string {\n if (!sectionTypes || sectionTypes.length === 0) {\n return markdown\n }\n\n const parsed = parseMarkdownSections(markdown)\n const filtered = parsed.filter((s) => sectionTypes.includes(s.type))\n\n if (filtered.length === 0) {\n return ''\n }\n\n // If overview is requested, include the title\n const includesOverview = sectionTypes.includes('overview')\n const overviewSection = filtered.find((s) => s.type === 'overview')\n\n if (includesOverview && overviewSection) {\n const otherSections = filtered.filter((s) => s.type !== 'overview')\n return [overviewSection.content, ...otherSections.map((s) => s.content)].join('\\n\\n')\n }\n\n return filtered.map((s) => s.content).join('\\n\\n')\n}\n","import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport { z } from 'zod'\n\nimport {\n getComponentContent,\n getComponentsList,\n slugToName,\n} from '../lib/component-data.js'\nimport { fuzzySearch } from '../lib/fuzzy-match.js'\nimport { type SectionType, extractSections } from '../lib/markdown-parser.js'\n\nconst sectionTypes = [\n 'overview',\n 'installation',\n 'import',\n 'examples',\n 'resources',\n] as const\n\nconst inputSchema = {\n slug: z.string().describe('Component slug (e.g., \"button\", \"alert-dialog\")'),\n sections: z\n .array(z.enum(sectionTypes))\n .optional()\n .describe(\n 'Filter sections: \"overview\", \"installation\", \"import\", \"examples\", \"resources\". Default: all.',\n ),\n}\n\ninterface GetComponentSuccessResult {\n slug: string\n name: string\n found: true\n content: string\n}\n\ninterface GetComponentNotFoundResult {\n slug: string\n found: false\n suggestions: Array<{ slug: string; name: string; score: number }>\n message: string\n}\n\nexport function registerGetComponentTool(server: McpServer): void {\n server.registerTool(\n 'get_component',\n {\n description:\n 'Get documentation for a Compose UI component. Supports fuzzy matching if exact slug not found.',\n inputSchema,\n },\n async ({ slug, sections }) => {\n // Try exact match first\n const content = await getComponentContent(slug)\n\n if (content) {\n // Extract requested sections or return full content\n const filteredContent = extractSections(\n content,\n sections as SectionType[] | undefined,\n )\n\n const result: GetComponentSuccessResult = {\n slug,\n name: slugToName(slug),\n found: true,\n content: filteredContent || content,\n }\n\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify(result, null, 2),\n },\n ],\n }\n }\n\n // No exact match - try fuzzy matching\n const allComponents = await getComponentsList()\n const fuzzyResults = fuzzySearch(slug, allComponents, (c) => c.slug, 0.2)\n\n const suggestions = fuzzyResults.slice(0, 5).map((r) => ({\n slug: r.item.slug,\n name: r.item.name,\n score: Math.round(r.score * 100) / 100,\n }))\n\n const suggestionText =\n suggestions.length > 0\n ? `Did you mean '${suggestions[0].slug}'?`\n : 'No similar components found.'\n\n const result: GetComponentNotFoundResult = {\n slug,\n found: false,\n suggestions,\n message: `Component '${slug}' not found. ${suggestionText}`,\n }\n\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify(result, null, 2),\n },\n ],\n }\n },\n )\n}\n","import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\n\nimport { registerFindComponentsTool } from './find-components.js'\nimport { registerGetComponentTool } from './get-component.js'\n\nexport function registerTools(server: McpServer): void {\n registerFindComponentsTool(server)\n registerGetComponentTool(server)\n}\n","import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\n\nimport { registerResources } from './resources/index.js'\nimport { registerTools } from './tools/index.js'\n\nexport function createServer(): McpServer {\n const server = new McpServer({\n name: 'compose-ui-mcp',\n version: '0.1.0',\n })\n\n registerResources(server)\n registerTools(server)\n\n return server\n}\n","#!/usr/bin/env node\n\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'\n\nimport { createServer } from './server.js'\n\nasync function main() {\n const server = createServer()\n const transport = new StdioServerTransport()\n\n await server.connect(transport)\n\n process.on('SIGINT', async () => {\n await server.close()\n process.exit(0)\n })\n}\n\nmain().catch((error) => {\n console.error('Server error:', error) // eslint-disable-line no-console\n process.exit(1)\n})\n"],"mappings":"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"}
|
package/dist/llms-full.txt
CHANGED
|
@@ -46,6 +46,24 @@
|
|
|
46
46
|
- Alert Dialog
|
|
47
47
|
- Accordion
|
|
48
48
|
|
|
49
|
+
## For AI Assistants
|
|
50
|
+
|
|
51
|
+
**MCP Server (Preferred)**
|
|
52
|
+
If you have access to MCP tools, use the `compose-ui` MCP server:
|
|
53
|
+
- `find_components` - Fuzzy search all components
|
|
54
|
+
- `get_component` - Get detailed docs for a specific component
|
|
55
|
+
|
|
56
|
+
**Styling Guidelines**
|
|
57
|
+
- Components are **pre-styled and ready to use** - do not add custom CSS, Tailwind classes, or inline styles
|
|
58
|
+
- Only add custom styling if the user explicitly requests it
|
|
59
|
+
- Use built-in variant props (e.g., `variant="outline"`, `size="sm"`) for different appearances
|
|
60
|
+
- For theming, use CSS variables - don't override component styles directly
|
|
61
|
+
|
|
62
|
+
**Best Practices**
|
|
63
|
+
- Always refer to this library as "Compose UI", not "Base UI" (Base UI is the underlying primitive library)
|
|
64
|
+
- Copy examples directly from the documentation - they are complete and working
|
|
65
|
+
- Use specific import paths: `import { Button } from '@lglab/compose-ui/button'` (not from '@lglab/compose-ui')
|
|
66
|
+
|
|
49
67
|
---
|
|
50
68
|
|
|
51
69
|
# Tooltip
|
package/dist/llms.txt
CHANGED
|
@@ -11,6 +11,24 @@ Key features:
|
|
|
11
11
|
- CSS variable-based theming (compatible with Tailwind v4)
|
|
12
12
|
- Tree-shakable ESM exports
|
|
13
13
|
|
|
14
|
+
## For AI Assistants
|
|
15
|
+
|
|
16
|
+
**MCP Server (Preferred)**
|
|
17
|
+
If you have access to MCP tools, use the `compose-ui` MCP server:
|
|
18
|
+
- `find_components` - Fuzzy search all components
|
|
19
|
+
- `get_component` - Get detailed docs for a specific component
|
|
20
|
+
|
|
21
|
+
**Styling Guidelines**
|
|
22
|
+
- Components are **pre-styled and ready to use** - do not add custom CSS, Tailwind classes, or inline styles
|
|
23
|
+
- Only add custom styling if the user explicitly requests it
|
|
24
|
+
- Use built-in variant props (e.g., `variant="outline"`, `size="sm"`) for different appearances
|
|
25
|
+
- For theming, use CSS variables - don't override component styles directly
|
|
26
|
+
|
|
27
|
+
**Best Practices**
|
|
28
|
+
- Always refer to this library as "Compose UI", not "Base UI" (Base UI is the underlying primitive library)
|
|
29
|
+
- Copy examples directly from the documentation - they are complete and working
|
|
30
|
+
- Use specific import paths: `import { Button } from '@lglab/compose-ui/button'` (not from '@lglab/compose-ui')
|
|
31
|
+
|
|
14
32
|
## Getting Started
|
|
15
33
|
|
|
16
34
|
- [Quick Start](https://compose-ui.dev/overview/quick-start): Installation and basic usage
|