@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 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/resources/components.ts
9
- const LLMS_DIR = resolve(dirname(fileURLToPath(import.meta.url)), "assets/llms");
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
- /* @__PURE__ */ registerTools(server);
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.1.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.mjs"
23
+ "compose-ui-mcp": "./dist/index.js"
24
24
  },
25
- "main": "./dist/index.mjs",
25
+ "main": "./dist/index.js",
26
26
  "types": "./dist/index.d.ts",
27
27
  "exports": {
28
28
  ".": {
29
- "import": "./dist/index.mjs",
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.mjs",
52
- "inspect": "npx @modelcontextprotocol/inspector node dist/index.mjs"
51
+ "start": "node dist/index.js",
52
+ "inspect": "npx @modelcontextprotocol/inspector node dist/index.js"
53
53
  }
54
54
  }