@lglab/compose-ui-mcp 0.1.0 → 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/dist/index.js +204 -4
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
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",
|
|
@@ -124,9 +128,205 @@ function registerResources(server) {
|
|
|
124
128
|
registerComponentDocResource(server);
|
|
125
129
|
}
|
|
126
130
|
|
|
131
|
+
//#endregion
|
|
132
|
+
//#region src/lib/fuzzy-match.ts
|
|
133
|
+
/**
|
|
134
|
+
* Calculate a fuzzy match score between a query and a target string.
|
|
135
|
+
* Returns a score from 0 to 1, where 1 is a perfect match.
|
|
136
|
+
*/
|
|
137
|
+
function fuzzyScore(query, target) {
|
|
138
|
+
const q = query.toLowerCase();
|
|
139
|
+
const t = target.toLowerCase();
|
|
140
|
+
if (q === t) return 1;
|
|
141
|
+
if (t.startsWith(q)) return .9;
|
|
142
|
+
if (t.includes(q)) return .7;
|
|
143
|
+
let queryIndex = 0;
|
|
144
|
+
let matchCount = 0;
|
|
145
|
+
for (const char of t) if (queryIndex < q.length && char === q[queryIndex]) {
|
|
146
|
+
matchCount++;
|
|
147
|
+
queryIndex++;
|
|
148
|
+
}
|
|
149
|
+
if (queryIndex === q.length) return .3 + matchCount / t.length * .3;
|
|
150
|
+
return new Set([...q].filter((c) => t.includes(c))).size / Math.max(q.length, t.length) * .3;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Search items using fuzzy matching.
|
|
154
|
+
* Returns items sorted by match score (highest first).
|
|
155
|
+
*/
|
|
156
|
+
function fuzzySearch(query, items, getSearchableText, minScore = .1) {
|
|
157
|
+
const results = [];
|
|
158
|
+
for (const item of items) {
|
|
159
|
+
const score = fuzzyScore(query, getSearchableText(item));
|
|
160
|
+
if (score >= minScore) results.push({
|
|
161
|
+
item,
|
|
162
|
+
score
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
results.sort((a, b) => b.score - a.score);
|
|
166
|
+
return results;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
//#endregion
|
|
170
|
+
//#region src/tools/find-components.ts
|
|
171
|
+
const inputSchema$1 = {
|
|
172
|
+
query: z.string().optional().describe("Fuzzy search query. Omit to list all components."),
|
|
173
|
+
limit: z.number().min(1).max(100).default(50).describe("Maximum number of results to return (default: 50)")
|
|
174
|
+
};
|
|
175
|
+
function registerFindComponentsTool(server) {
|
|
176
|
+
server.registerTool("find_components", {
|
|
177
|
+
description: "Find Compose UI components. Call without query to list all, or with query for fuzzy search.",
|
|
178
|
+
inputSchema: inputSchema$1
|
|
179
|
+
}, async ({ query, limit }) => {
|
|
180
|
+
const allComponents = await getComponentsList();
|
|
181
|
+
let components;
|
|
182
|
+
if (query) components = fuzzySearch(query, allComponents, (c) => `${c.name} ${c.slug}`).slice(0, limit ?? 50).map((r) => ({
|
|
183
|
+
slug: r.item.slug,
|
|
184
|
+
name: r.item.name,
|
|
185
|
+
description: r.item.description
|
|
186
|
+
}));
|
|
187
|
+
else components = allComponents.slice(0, limit ?? 50).map((c) => ({
|
|
188
|
+
slug: c.slug,
|
|
189
|
+
name: c.name,
|
|
190
|
+
description: c.description
|
|
191
|
+
}));
|
|
192
|
+
const result = {
|
|
193
|
+
count: components.length,
|
|
194
|
+
components
|
|
195
|
+
};
|
|
196
|
+
return { content: [{
|
|
197
|
+
type: "text",
|
|
198
|
+
text: JSON.stringify(result, null, 2)
|
|
199
|
+
}] };
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
//#endregion
|
|
204
|
+
//#region src/lib/markdown-parser.ts
|
|
205
|
+
const SECTION_MAPPINGS = {
|
|
206
|
+
installation: "installation",
|
|
207
|
+
import: "import",
|
|
208
|
+
examples: "examples",
|
|
209
|
+
resources: "resources"
|
|
210
|
+
};
|
|
211
|
+
/**
|
|
212
|
+
* Parse markdown content into sections based on ## headings.
|
|
213
|
+
*/
|
|
214
|
+
function parseMarkdownSections(markdown) {
|
|
215
|
+
const lines = markdown.split("\n");
|
|
216
|
+
const sections = [];
|
|
217
|
+
let title = "";
|
|
218
|
+
const overviewLines = [];
|
|
219
|
+
let currentSection = null;
|
|
220
|
+
const rawSections = [];
|
|
221
|
+
for (const line of lines) {
|
|
222
|
+
if (line.startsWith("# ") && !title) {
|
|
223
|
+
title = line.slice(2).trim();
|
|
224
|
+
continue;
|
|
225
|
+
}
|
|
226
|
+
if (line.startsWith("## ")) {
|
|
227
|
+
if (currentSection) rawSections.push(currentSection);
|
|
228
|
+
else if (overviewLines.length > 0) sections.push({
|
|
229
|
+
type: "overview",
|
|
230
|
+
title: title || "Overview",
|
|
231
|
+
content: `# ${title}\n\n${overviewLines.join("\n").trim()}`
|
|
232
|
+
});
|
|
233
|
+
currentSection = {
|
|
234
|
+
heading: line.slice(3).trim(),
|
|
235
|
+
content: ""
|
|
236
|
+
};
|
|
237
|
+
continue;
|
|
238
|
+
}
|
|
239
|
+
if (currentSection) currentSection.content += line + "\n";
|
|
240
|
+
else if (title) overviewLines.push(line);
|
|
241
|
+
}
|
|
242
|
+
if (currentSection) rawSections.push(currentSection);
|
|
243
|
+
else if (overviewLines.length > 0 && sections.length === 0) sections.push({
|
|
244
|
+
type: "overview",
|
|
245
|
+
title: title || "Overview",
|
|
246
|
+
content: `# ${title}\n\n${overviewLines.join("\n").trim()}`
|
|
247
|
+
});
|
|
248
|
+
for (const raw of rawSections) {
|
|
249
|
+
const sectionType = SECTION_MAPPINGS[raw.heading.toLowerCase()] || "overview";
|
|
250
|
+
sections.push({
|
|
251
|
+
type: sectionType,
|
|
252
|
+
title: raw.heading,
|
|
253
|
+
content: `## ${raw.heading}\n${raw.content.trim()}`
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
return sections;
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Extract specific sections from markdown content.
|
|
260
|
+
* If no sections are specified, returns the full content.
|
|
261
|
+
*/
|
|
262
|
+
function extractSections(markdown, sectionTypes) {
|
|
263
|
+
if (!sectionTypes || sectionTypes.length === 0) return markdown;
|
|
264
|
+
const filtered = parseMarkdownSections(markdown).filter((s) => sectionTypes.includes(s.type));
|
|
265
|
+
if (filtered.length === 0) return "";
|
|
266
|
+
const includesOverview = sectionTypes.includes("overview");
|
|
267
|
+
const overviewSection = filtered.find((s) => s.type === "overview");
|
|
268
|
+
if (includesOverview && overviewSection) {
|
|
269
|
+
const otherSections = filtered.filter((s) => s.type !== "overview");
|
|
270
|
+
return [overviewSection.content, ...otherSections.map((s) => s.content)].join("\n\n");
|
|
271
|
+
}
|
|
272
|
+
return filtered.map((s) => s.content).join("\n\n");
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
//#endregion
|
|
276
|
+
//#region src/tools/get-component.ts
|
|
277
|
+
const inputSchema = {
|
|
278
|
+
slug: z.string().describe("Component slug (e.g., \"button\", \"alert-dialog\")"),
|
|
279
|
+
sections: z.array(z.enum([
|
|
280
|
+
"overview",
|
|
281
|
+
"installation",
|
|
282
|
+
"import",
|
|
283
|
+
"examples",
|
|
284
|
+
"resources"
|
|
285
|
+
])).optional().describe("Filter sections: \"overview\", \"installation\", \"import\", \"examples\", \"resources\". Default: all.")
|
|
286
|
+
};
|
|
287
|
+
function registerGetComponentTool(server) {
|
|
288
|
+
server.registerTool("get_component", {
|
|
289
|
+
description: "Get documentation for a Compose UI component. Supports fuzzy matching if exact slug not found.",
|
|
290
|
+
inputSchema
|
|
291
|
+
}, async ({ slug, sections }) => {
|
|
292
|
+
const content = await getComponentContent(slug);
|
|
293
|
+
if (content) {
|
|
294
|
+
const filteredContent = extractSections(content, sections);
|
|
295
|
+
const result = {
|
|
296
|
+
slug,
|
|
297
|
+
name: slugToName(slug),
|
|
298
|
+
found: true,
|
|
299
|
+
content: filteredContent || content
|
|
300
|
+
};
|
|
301
|
+
return { content: [{
|
|
302
|
+
type: "text",
|
|
303
|
+
text: JSON.stringify(result, null, 2)
|
|
304
|
+
}] };
|
|
305
|
+
}
|
|
306
|
+
const suggestions = fuzzySearch(slug, await getComponentsList(), (c) => c.slug, .2).slice(0, 5).map((r) => ({
|
|
307
|
+
slug: r.item.slug,
|
|
308
|
+
name: r.item.name,
|
|
309
|
+
score: Math.round(r.score * 100) / 100
|
|
310
|
+
}));
|
|
311
|
+
const result = {
|
|
312
|
+
slug,
|
|
313
|
+
found: false,
|
|
314
|
+
suggestions,
|
|
315
|
+
message: `Component '${slug}' not found. ${suggestions.length > 0 ? `Did you mean '${suggestions[0].slug}'?` : "No similar components found."}`
|
|
316
|
+
};
|
|
317
|
+
return { content: [{
|
|
318
|
+
type: "text",
|
|
319
|
+
text: JSON.stringify(result, null, 2)
|
|
320
|
+
}] };
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
|
|
127
324
|
//#endregion
|
|
128
325
|
//#region src/tools/index.ts
|
|
129
|
-
function registerTools(server) {
|
|
326
|
+
function registerTools(server) {
|
|
327
|
+
registerFindComponentsTool(server);
|
|
328
|
+
registerGetComponentTool(server);
|
|
329
|
+
}
|
|
130
330
|
|
|
131
331
|
//#endregion
|
|
132
332
|
//#region src/server.ts
|
|
@@ -136,7 +336,7 @@ function createServer() {
|
|
|
136
336
|
version: "0.1.0"
|
|
137
337
|
});
|
|
138
338
|
registerResources(server);
|
|
139
|
-
|
|
339
|
+
registerTools(server);
|
|
140
340
|
return server;
|
|
141
341
|
}
|
|
142
342
|
|
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## 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","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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lglab/compose-ui-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "MCP server exposing compose-ui library documentation to AI tools",
|
|
5
5
|
"author": "LGLab",
|
|
6
6
|
"license": "MIT",
|
|
@@ -20,13 +20,13 @@
|
|
|
20
20
|
],
|
|
21
21
|
"type": "module",
|
|
22
22
|
"bin": {
|
|
23
|
-
"compose-ui-mcp": "./dist/index.
|
|
23
|
+
"compose-ui-mcp": "./dist/index.js"
|
|
24
24
|
},
|
|
25
|
-
"main": "./dist/index.
|
|
25
|
+
"main": "./dist/index.js",
|
|
26
26
|
"types": "./dist/index.d.ts",
|
|
27
27
|
"exports": {
|
|
28
28
|
".": {
|
|
29
|
-
"import": "./dist/index.
|
|
29
|
+
"import": "./dist/index.js",
|
|
30
30
|
"types": "./dist/index.d.ts"
|
|
31
31
|
}
|
|
32
32
|
},
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"prebuild": "pnpm copy:llms",
|
|
49
49
|
"build": "tsdown",
|
|
50
50
|
"dev": "tsdown --watch",
|
|
51
|
-
"start": "node dist/index.
|
|
52
|
-
"inspect": "npx @modelcontextprotocol/inspector node dist/index.
|
|
51
|
+
"start": "node dist/index.js",
|
|
52
|
+
"inspect": "npx @modelcontextprotocol/inspector node dist/index.js"
|
|
53
53
|
}
|
|
54
54
|
}
|