#
tokens: 9285/50000 15/15 files
lines: on (toggle) GitHub
raw markdown copy reset
# Directory Structure

```
├── .gitignore
├── .husky
│   └── commit-msg
├── .npmignore
├── .npmrc
├── commitlint.config.mjs
├── LICENSE
├── package.json
├── pnpm-lock.yaml
├── public
│   └── logo.svg
├── README.md
├── src
│   ├── lib
│   │   ├── categories.ts
│   │   └── config.ts
│   ├── server.ts
│   └── utils
│       ├── api.ts
│       ├── formatters.ts
│       ├── index.ts
│       └── schemas.ts
└── tsconfig.json
```

# Files

--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------

```
1 | tag-version-prefix="v"
2 | message="chore(release): %s"
```

--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------

```
 1 | .DS_Store
 2 | dist/
 3 | node_modules/
 4 | 
 5 | tsconfig.tsbuildinfo
 6 | .husky/_
 7 | 
 8 | .env
 9 | .env.*
10 | 
```

--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------

```
 1 | # Source files
 2 | src/
 3 | tsconfig.json
 4 | tsconfig.tsbuildinfo
 5 | 
 6 | # Development files
 7 | .git/
 8 | .gitignore
 9 | .DS_Store
10 | 
11 | # Node modules and lock files
12 | node_modules/
13 | pnpm-lock.yaml
14 | yarn.lock
15 | package-lock.json
16 | 
17 | # Development and testing
18 | *.log
19 | coverage/
20 | .nyc_output/
21 | .env
22 | .env.local
23 | .env.*.local
24 | 
25 | # IDE files
26 | .vscode/
27 | .idea/
28 | *.swp
29 | *.swo
30 | 
31 | # Build artifacts (keep only what's in "files" array)
32 | # Everything else will be excluded by default since we specified "files": ["dist"]
33 | 
```

--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------

```markdown
 1 | <!-- PROJECT LOGO -->
 2 | <br />
 3 | <div align="center">
 4 |   <a href="https://github.com/stackzero-labs/ui">
 5 |     <img src="public/logo.svg" alt="Logo" width="80" height="80">
 6 |   </a>
 7 | 
 8 |   <h3 align="center">@stackzero-labs/mcp</h3>
 9 | 
10 |   <p align="center">
11 |     Official MCP (Model Context Protocol) server for stackzero-labs/ui.
12 |     <br />
13 |     <a href="https://ui.stackzero.co"><strong>Official Docs »</strong></a>
14 |     <br />
15 |     <br />
16 |     <a href="https://ui.stackzero.co/get-started">Get started</a>
17 |     &middot;
18 |     <a href="https://github.com/stackzero-labs/mcp/issues/new?labels=bug&template=bug-report---.md">Report Bug</a>
19 |     &middot;
20 |     <a href="https://github.com/stackzero-labs/mcp/issues/new?labels=enhancement&template=feature-request---.md">Request Feature</a>
21 |   </p>
22 | </div>
23 | 
24 | ## Overview
25 | 
26 | This package allows you to run a model context server for stackzero-labs/ui components, enabling you to use the MCP protocol with your applications.
27 | 
28 | ## 1-click install in Cursor
29 | 
30 | [![Install MCP Server](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/install-mcp?name=%40stackzero-labs%2Fmcp&config=eyJjb21tYW5kIjoibnB4IC15IEBzdGFja3plcm8tbGFicy9tY3BAbGF0ZXN0In0%3D)
31 | 
32 | ## Installation
33 | 
34 | ```bash
35 | npm install @stackzero-labs/mcp
36 | ```
37 | 
38 | ## Usage
39 | 
40 | ### As a standalone server
41 | 
42 | ```bash
43 | npx @stackzero-labs/mcp
44 | ```
45 | 
46 | ### In Claude Desktop
47 | 
48 | Add to your Claude Desktop configuration:
49 | 
50 | ```json
51 | {
52 |   "mcpServers": {
53 |     "@stackzero-labs/mcp": {
54 |       "command": "npx",
55 |       "args": ["-y", "@stackzero-labs/mcp@latest"]
56 |     }
57 |   }
58 | }
59 | ```
60 | 
61 | ### In Cursor (manual setup)
62 | 
63 | Go to Cursor settings, select `MCP`. Add to your Cursor configuration:
64 | 
65 | ```json
66 | {
67 |   "mcpServers": {
68 |     "@stackzero-labs/mcp": {
69 |       "command": "npx",
70 |       "args": ["-y", "@stackzero-labs/mcp@latest"]
71 |     }
72 |   }
73 | }
74 | ```
75 | 
76 | ### Development
77 | 
78 | ```bash
79 | # Install dependencies
80 | pnpm install
81 | 
82 | # Build the project
83 | pnpm build
84 | 
85 | # Run in development mode
86 | pnpm dev
87 | 
88 | # Inspect the MCP server
89 | pnpm inspect
90 | ```
91 | 
92 | ## License
93 | 
94 | See [LICENSE](LICENSE) for details.
95 | 
```

--------------------------------------------------------------------------------
/src/utils/index.ts:
--------------------------------------------------------------------------------

```typescript
1 | export * from "./api.js";
2 | export * from "./formatters.js";
3 | export * from "./schemas.js";
4 | 
```

--------------------------------------------------------------------------------
/src/lib/config.ts:
--------------------------------------------------------------------------------

```typescript
 1 | /**
 2 |  *  General configuration for MCP service
 3 |  */
 4 | export const mcpConfig = {
 5 |   projectName: "@stackzero-labs/ui",
 6 |   baseUrl: "https://ui.stackzero.co",
 7 |   registryUrl: "https://ui.stackzero.co/r",
 8 |   registryFileUrl: "https://ui.stackzero.co/registry.json",
 9 | };
10 | 
```

--------------------------------------------------------------------------------
/src/utils/formatters.ts:
--------------------------------------------------------------------------------

```typescript
 1 | /**
 2 |  * Formats a component name by converting it from kebab-case to PascalCase.
 3 |  * @param componentName
 4 |  * @returns
 5 |  */
 6 | export function formatComponentName(componentName: string): string {
 7 |   return componentName
 8 |     .split("-")
 9 |     .map((part) => {
10 |       return part.charAt(0).toUpperCase() + part.slice(1);
11 |     })
12 |     .join("");
13 | }
14 | 
```

--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "compilerOptions": {
 3 |     "target": "ES2022",
 4 |     "module": "ESNext",
 5 |     "moduleResolution": "node",
 6 |     "outDir": "dist",
 7 |     "rootDir": "src",
 8 |     "sourceMap": true,
 9 |     "declaration": true,
10 |     "strict": true,
11 |     "esModuleInterop": true,
12 |     "allowSyntheticDefaultImports": true,
13 |     "skipLibCheck": true
14 |   },
15 |   "include": ["src/**/*"],
16 |   "exclude": ["node_modules", "dist"]
17 | }
18 | 
```

--------------------------------------------------------------------------------
/public/logo.svg:
--------------------------------------------------------------------------------

```
 1 | <svg width="217" height="216" viewBox="0 0 217 216" fill="none" xmlns="http://www.w3.org/2000/svg">
 2 | <g clip-path="url(#clip0_1134_83)">
 3 | <path d="M91.8543 167.855C112.307 173.221 135.092 167.808 151.24 151.659C167.389 135.511 172.803 112.726 167.437 92.2731L91.8543 167.855Z" fill="#00FF9D"/>
 4 | <path d="M158.581 74.1351C156.455 71.0144 154.008 68.047 151.241 65.2791C127.387 41.426 88.714 41.426 64.8609 65.2791C41.0078 89.1322 41.0078 127.806 64.8609 151.659C67.6288 154.427 70.5962 156.873 73.7169 158.999L158.581 74.1351Z" fill="#8940FF"/>
 5 | </g>
 6 | <defs>
 7 | <clipPath id="clip0_1134_83">
 8 | <rect width="152.699" height="152.699" fill="white" transform="translate(108.051 215.949) rotate(-135)"/>
 9 | </clipPath>
10 | </defs>
11 | </svg>
12 | 
```

--------------------------------------------------------------------------------
/commitlint.config.mjs:
--------------------------------------------------------------------------------

```
 1 | const Configuration = {
 2 |   extends: ["@commitlint/config-conventional"],
 3 |   rules: {
 4 |     "type-enum": [
 5 |       2,
 6 |       "always",
 7 |       [
 8 |         "feat", // A new feature
 9 |         "fix", // A bug fix
10 |         "docs", // Documentation only changes
11 |         "style", // Changes that do not affect the meaning of the code
12 |         "refactor", // A code change that neither fixes a bug nor adds a feature
13 |         "perf", // A code change that improves performance
14 |         "test", // Adding missing tests or correcting existing tests
15 |         "chore", // Changes to the build process or auxiliary tools
16 |         "ci", // Changes to CI configuration files and scripts
17 |         "build", // Changes that affect the build system or external dependencies
18 |         "revert", // Reverts a previous commit
19 |       ],
20 |     ],
21 |     "type-case": [2, "always", "lower-case"],
22 |     "type-empty": [2, "never"],
23 |     "scope-case": [2, "always", "lower-case"],
24 |     "subject-case": [
25 |       2,
26 |       "never",
27 |       ["sentence-case", "start-case", "pascal-case", "upper-case"],
28 |     ],
29 |     "subject-empty": [2, "never"],
30 |     "subject-full-stop": [2, "never", "."],
31 |     "header-max-length": [2, "always", 100],
32 |     "body-leading-blank": [1, "always"],
33 |     "body-max-line-length": [2, "always", 100],
34 |     "footer-leading-blank": [1, "always"],
35 |     "footer-max-line-length": [2, "always", 100],
36 |   },
37 | };
38 | 
39 | export default Configuration;
40 | 
```

--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "name": "@stackzero-labs/mcp",
 3 |   "version": "0.4.0",
 4 |   "author": "@stackzero-labs",
 5 |   "keywords": [
 6 |     "mcp",
 7 |     "model-context-protocol",
 8 |     "ai",
 9 |     "claude",
10 |     "server"
11 |   ],
12 |   "license": "MIT",
13 |   "description": "MCP (Model Context Protocol) server for stackzero-labs/ui",
14 |   "homepage": "https://ui.stackzero.co",
15 |   "repository": {
16 |     "type": "git",
17 |     "url": "git+https://github.com/stackzero-labs/mcp.git"
18 |   },
19 |   "bugs": {
20 |     "url": "https://github.com/stackzero-labs/mcp/issues"
21 |   },
22 |   "scripts": {
23 |     "build": "tsup src/server.ts --format esm,cjs --dts --out-dir dist",
24 |     "build:old": "tsc && shx chmod +x dist/*.js",
25 |     "start": "node dist/server.js",
26 |     "dev": "tsx watch src/server.ts",
27 |     "inspect": "mcp-inspector node dist/server.js",
28 |     "prepublishOnly": "pnpm run build",
29 |     "prepare": "husky"
30 |   },
31 |   "type": "module",
32 |   "main": "./dist/server.js",
33 |   "module": "./dist/server.js",
34 |   "types": "./dist/server.d.ts",
35 |   "bin": {
36 |     "mcp": "./dist/server.js"
37 |   },
38 |   "files": [
39 |     "dist"
40 |   ],
41 |   "dependencies": {
42 |     "@modelcontextprotocol/sdk": "^1.12.3",
43 |     "zod": "^3.25.64"
44 |   },
45 |   "devDependencies": {
46 |     "@commitlint/cli": "^19.8.1",
47 |     "@commitlint/config-conventional": "^19.8.1",
48 |     "@modelcontextprotocol/inspector": "^0.14.2",
49 |     "@types/node": "^22.14.1",
50 |     "husky": "^9.1.7",
51 |     "shx": "^0.4.0",
52 |     "tsup": "^8.5.0",
53 |     "tsx": "^4.20.3",
54 |     "typescript": "^5.8.3"
55 |   }
56 | }
57 | 
```

--------------------------------------------------------------------------------
/src/utils/schemas.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { z } from "zod";
 2 | import { registry } from "zod/dist/types/v4";
 3 | 
 4 | export const ComponentSchema = z.object({
 5 |   name: z.string(),
 6 |   type: z.string(),
 7 |   description: z.string().optional(),
 8 | });
 9 | 
10 | export const BlockSchema = ComponentSchema.extend({
11 |   name: z.string(),
12 |   type: z.string(),
13 |   description: z.string().optional(),
14 | });
15 | 
16 | const ExampleSchema = z.object({
17 |   name: z.string(),
18 |   type: z.string(),
19 |   description: z.string(),
20 |   content: z.string(),
21 | });
22 | 
23 | export const IndividualComponentSchema = ComponentSchema.extend({
24 |   install: z.string(),
25 |   content: z.string(),
26 |   examples: z.array(ExampleSchema),
27 | });
28 | 
29 | export const IndividualBlockSchema = BlockSchema.extend({
30 |   install: z.string(),
31 |   content: z.string(),
32 |   examples: z.array(ExampleSchema),
33 | });
34 | 
35 | export const ComponentDetailSchema = z.object({
36 |   name: z.string(),
37 |   type: z.string(),
38 |   files: z.array(
39 |     z.object({
40 |       content: z.string(),
41 |     })
42 |   ),
43 | });
44 | 
45 | export const BlockDetailSchema = z.object({
46 |   name: z.string(),
47 |   type: z.string(),
48 |   registryDependencies: z.array(z.string()),
49 |   files: z.array(
50 |     z.object({
51 |       content: z.string(),
52 |     })
53 |   ),
54 | });
55 | 
56 | export const ExampleComponentSchema = z.object({
57 |   name: z.string(),
58 |   type: z.string(),
59 |   description: z.string().optional(),
60 |   registryDependencies: z.array(z.string()),
61 | });
62 | 
63 | export const ExampleDetailSchema = z.object({
64 |   name: z.string(),
65 |   type: z.string(),
66 |   description: z.string(),
67 |   files: z.array(
68 |     z.object({
69 |       content: z.string(),
70 |     })
71 |   ),
72 | });
73 | 
```

--------------------------------------------------------------------------------
/src/lib/categories.ts:
--------------------------------------------------------------------------------

```typescript
 1 | // Component category definitions
 2 | export const componentCategories = {
 3 |   Ratings: [
 4 |     "star-rating-basic",
 5 |     "star-rating-fractions",
 6 |     "upvote-rating-basic",
 7 |     "upvote-rating-animated",
 8 |     "face-rating-basic",
 9 |     "face-rating-gradient",
10 |   ],
11 |   Images: ["image-viewer-basic", "image-viewer-motion", "image-carousel-basic"],
12 |   Products: [
13 |     "price-format-basic",
14 |     "price-format-sale",
15 |     "quantity-input-basic",
16 |     "variant-color-selector-basic",
17 |     "variant-selector-basic",
18 |     "variant-selector-images",
19 |     "variant-selector-multiple",
20 |   ],
21 |   Inputs: ["input-icon", "phone-number-input-basic"],
22 | };
23 | 
24 | export const blocksCategories = {
25 |   Addresses: ["address-01-block", "address-02-block"],
26 |   Banners: [
27 |     "banner-01-block",
28 |     "banner-02-block",
29 |     "banner-03-block",
30 |     "banner-04-block",
31 |     "banner-05-block",
32 |     "banner-06-block",
33 |     "banner-07-block",
34 |     "banner-08-block",
35 |     "banner-09-block",
36 |     "banner-10-block",
37 |     "banner-11-block",
38 |     "banner-12-block",
39 |   ],
40 |   ProductCards: [
41 |     "product-card-01-block",
42 |     "product-card-02-block",
43 |     "product-card-03-block",
44 |     "product-card-04-block",
45 |     "product-card-05-block",
46 |     "product-card-06-block",
47 |     "product-card-07-block",
48 |     "product-card-08-block",
49 |     "product-card-09-block",
50 |     "product-card-10-block",
51 |     "product-card-11-block",
52 |     "product-card-12-block",
53 |     "product-card-13-block",
54 |   ],
55 |   ProductVariants: [
56 |     "product-variant-01-block",
57 |     "product-variant-02-block",
58 |     "product-variant-03-block",
59 |     "product-variant-04-block",
60 |     "product-variant-05-block",
61 |   ],
62 |   Reviews: [
63 |     "review-01-block",
64 |     "review-02-block",
65 |     "review-03-block",
66 |     "review-04-block",
67 |     "review-05-block",
68 |     "review-06-block",
69 |     "review-07-block",
70 |     "review-08-block",
71 |     "review-09-block",
72 |     "review-10-block",
73 |   ],
74 |   Carts: ["cart-01-block"],
75 | };
76 | 
```

--------------------------------------------------------------------------------
/src/utils/api.ts:
--------------------------------------------------------------------------------

```typescript
  1 | import { mcpConfig } from "../lib/config.js";
  2 | import {
  3 |   BlockDetailSchema,
  4 |   BlockSchema,
  5 |   ComponentDetailSchema,
  6 |   ComponentSchema,
  7 |   ExampleComponentSchema,
  8 |   ExampleDetailSchema,
  9 | } from "./schemas.js";
 10 | 
 11 | /**
 12 |  *  Fetches all UI components from the registry.
 13 |  *  @returns An array of components with their details.
 14 |  */
 15 | export async function fetchUIComponents() {
 16 |   try {
 17 |     const response = await fetch(mcpConfig.registryFileUrl);
 18 |     if (!response.ok) {
 19 |       throw new Error(
 20 |         `Failed to fetch registry.json: ${response.statusText} - Status: ${response.status}`
 21 |       );
 22 |     }
 23 |     const data = await response.json();
 24 | 
 25 |     return data.registry
 26 |       .filter((item: any) => item.type === "registry:component")
 27 |       .map((item: any) => {
 28 |         try {
 29 |           return ComponentSchema.parse({
 30 |             name: item.name,
 31 |             type: item.type,
 32 |             description: item.description,
 33 |           });
 34 |         } catch (parseError) {
 35 |           return null;
 36 |         }
 37 |       });
 38 |   } catch (error) {
 39 |     return [];
 40 |   }
 41 | }
 42 | 
 43 | /**
 44 |  * Fetches all UI blocks from the registry.
 45 |  * @returns An array of UI blocks.
 46 |  */
 47 | export async function fetchUIBlocks() {
 48 |   try {
 49 |     const response = await fetch(mcpConfig.registryFileUrl);
 50 |     if (!response.ok) {
 51 |       throw new Error(
 52 |         `Failed to fetch registry.json: ${response.statusText} - Status: ${response.status}`
 53 |       );
 54 |     }
 55 |     const data = await response.json();
 56 | 
 57 |     return data.registry
 58 |       .filter((item: any) => item.type === "registry:block")
 59 |       .map((item: any) => {
 60 |         try {
 61 |           return BlockSchema.parse({
 62 |             name: item.name,
 63 |             type: item.type,
 64 |             description: item.description,
 65 |           });
 66 |         } catch (parseError) {
 67 |           return null;
 68 |         }
 69 |       });
 70 |   } catch (error) {
 71 |     return [];
 72 |   }
 73 | }
 74 | 
 75 | /**
 76 |  * Fetches details for a specific component from the registry.
 77 |  * @param componentName The name of the component.
 78 |  * @returns The details of the component.
 79 |  */
 80 | export async function fetchComponentDetails(componentName: string) {
 81 |   try {
 82 |     const response = await fetch(
 83 |       `${mcpConfig.registryUrl}/${componentName}.json`
 84 |     );
 85 |     if (!response.ok) {
 86 |       throw new Error(
 87 |         `Failed to fetch component ${componentName}: ${response.statusText}`
 88 |       );
 89 |     }
 90 |     const data = await response.json();
 91 |     return ComponentDetailSchema.parse(data);
 92 |   } catch (error) {
 93 |     console.error(`Error fetching component ${componentName}:`, error);
 94 |     throw error;
 95 |   }
 96 | }
 97 | 
 98 | /**
 99 |  * Fetches details for a specific component from the registry.
100 |  * @param componentName The name of the component.
101 |  * @returns The details of the component.
102 |  */
103 | export async function fetchBlockDetails(blockName: string) {
104 |   try {
105 |     const response = await fetch(`${mcpConfig.registryUrl}/${blockName}.json`);
106 |     if (!response.ok) {
107 |       throw new Error(
108 |         `Failed to fetch block ${blockName}: ${response.statusText}`
109 |       );
110 |     }
111 |     const data = await response.json();
112 |     return BlockDetailSchema.parse(data);
113 |   } catch (error) {
114 |     console.error(`Error fetching block ${blockName}:`, error);
115 |     throw error;
116 |   }
117 | }
118 | 
119 | /**
120 |  * Fetches example components from the registry.
121 |  * @returns An array of example components.
122 |  */
123 | export async function fetchExampleComponents() {
124 |   try {
125 |     const response = await fetch(mcpConfig.registryFileUrl);
126 |     const data = await response.json();
127 | 
128 |     return data.registry
129 |       .filter((item: any) => item.type === "registry:example")
130 |       .map((item: any) => {
131 |         return ExampleComponentSchema.parse({
132 |           name: item.name,
133 |           type: item.type,
134 |           description: item.description,
135 |           registryDependencies: item.registryDependencies,
136 |         });
137 |       });
138 |   } catch (error) {
139 |     console.error("Error fetching example components:", error);
140 |     return [];
141 |   }
142 | }
143 | 
144 | /**
145 |  * Fetches details for a specific example component.
146 |  * @param exampleName The name of the example component.
147 |  * @returns The details of the example component.
148 |  */
149 | export async function fetchExampleDetails(exampleName: string) {
150 |   try {
151 |     const response = await fetch(`${mcpConfig.registryUrl}/${exampleName}`);
152 |     if (!response.ok) {
153 |       throw new Error(
154 |         `Failed to fetch example details for ${exampleName}: ${response.statusText}`
155 |       );
156 |     }
157 |     const data = await response.json();
158 |     return ExampleDetailSchema.parse(data);
159 |   } catch (error) {
160 |     console.error(`Error fetching example details for ${exampleName}:`, error);
161 |     throw error;
162 |   }
163 | }
164 | 
```

--------------------------------------------------------------------------------
/src/server.ts:
--------------------------------------------------------------------------------

```typescript
  1 | #!/usr/bin/env node
  2 | 
  3 | import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
  4 | import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
  5 | import {
  6 |   IndividualComponentSchema,
  7 |   fetchComponentDetails,
  8 |   fetchBlockDetails,
  9 |   fetchExampleComponents,
 10 |   fetchExampleDetails,
 11 |   fetchUIBlocks,
 12 |   fetchUIComponents,
 13 |   IndividualBlockSchema,
 14 | } from "./utils/index.js";
 15 | import { formatComponentName } from "./utils/formatters.js";
 16 | import { blocksCategories, componentCategories } from "./lib/categories.js";
 17 | 
 18 | // Initialize the MCP Server
 19 | const server = new McpServer({
 20 |   name: "@stackzero-labs/mcp",
 21 |   version: "0.2.0",
 22 | });
 23 | 
 24 | // Register the main tool for getting all components
 25 | server.tool(
 26 |   "getUIComponents",
 27 |   "Provides a comprehensive list of all stackzero-labs/ui components.",
 28 |   {},
 29 |   async () => {
 30 |     try {
 31 |       const uiComponents = await fetchUIComponents();
 32 | 
 33 |       return {
 34 |         content: [
 35 |           {
 36 |             type: "text",
 37 |             text: JSON.stringify(uiComponents, null, 2),
 38 |           },
 39 |         ],
 40 |       };
 41 |     } catch (error) {
 42 |       return {
 43 |         content: [
 44 |           {
 45 |             type: "text",
 46 |             text: "Failed to fetch stackzero-labs/ui components",
 47 |           },
 48 |         ],
 49 |         isError: true,
 50 |       };
 51 |     }
 52 |   }
 53 | );
 54 | 
 55 | // Register the main tool for getting all blocks
 56 | server.tool(
 57 |   "getUIBlocks",
 58 |   "Provides a comprehensive list of all stackzero-labs/ui blocks.",
 59 |   {},
 60 |   async () => {
 61 |     try {
 62 |       const uiBlocks = await fetchUIBlocks();
 63 |       return {
 64 |         content: [
 65 |           {
 66 |             type: "text",
 67 |             text: JSON.stringify(uiBlocks, null, 2),
 68 |           },
 69 |         ],
 70 |       };
 71 |     } catch (error) {
 72 |       return {
 73 |         content: [
 74 |           {
 75 |             type: "text",
 76 |             text: "Failed to fetch stackzero-labs/ui blocks",
 77 |           },
 78 |         ],
 79 |       };
 80 |     }
 81 |   }
 82 | );
 83 | 
 84 | /**
 85 |  * Creates a registry mapping component names to their example implementations.
 86 |  * @param exampleComponentList - The list of example components to process.
 87 |  * @returns A map where each key is a component name and the value is an array of example names.
 88 |  */
 89 | function createComponentExampleRegistry(
 90 |   exampleComponentList: Array<{
 91 |     name: string;
 92 |     registryDependencies?: string[];
 93 |   }>
 94 | ): Map<string, string[]> {
 95 |   const componentRegistry = new Map<string, string[]>();
 96 | 
 97 |   for (const exampleItem of exampleComponentList) {
 98 |     if (
 99 |       exampleItem.registryDependencies &&
100 |       Array.isArray(exampleItem.registryDependencies)
101 |     ) {
102 |       for (const dependencyUrl of exampleItem.registryDependencies) {
103 |         if (
104 |           typeof dependencyUrl === "string" &&
105 |           dependencyUrl.includes("stackzero.co")
106 |         ) {
107 |           const nameExtraction = dependencyUrl.match(/\/r\/([^\/]+)$/);
108 |           if (nameExtraction && nameExtraction[1]) {
109 |             const extractedComponentName = nameExtraction[1];
110 |             if (!componentRegistry.has(extractedComponentName)) {
111 |               componentRegistry.set(extractedComponentName, []);
112 |             }
113 |             if (
114 |               !componentRegistry
115 |                 .get(extractedComponentName)
116 |                 ?.includes(exampleItem.name)
117 |             ) {
118 |               componentRegistry
119 |                 .get(extractedComponentName)
120 |                 ?.push(exampleItem.name);
121 |             }
122 |           }
123 |         }
124 |       }
125 |     }
126 |   }
127 |   return componentRegistry;
128 | }
129 | 
130 | /**
131 |  * Fetches components and blocks by category, processing each category's components and blocks.
132 |  * @param categoryComponents - The list of component names in the category.
133 |  * @param categoryBlocks - The list of block names in the category.
134 |  * @returns An object containing the processed components and blocks.
135 |  */
136 | async function fetchComponentsByCategory(
137 |   categoryComponents: string[],
138 |   allComponents: any[],
139 |   exampleNamesByComponent: Map<string, string[]>
140 | ) {
141 |   const componentResults = [];
142 | 
143 |   for (const componentName of categoryComponents) {
144 |     const component = allComponents.find((c) => c.name === componentName);
145 |     if (!component) continue;
146 | 
147 |     try {
148 |       const componentDetails = await fetchComponentDetails(componentName);
149 |       const componentContent = componentDetails.files[0]?.content;
150 | 
151 |       const relevantExampleNames =
152 |         exampleNamesByComponent.get(componentName) || [];
153 | 
154 |       // Generate installation instructions
155 |       const installInstructions = `You can install the component/blocks using  \
156 |       shadcn/ui CLI. For example, with npx: npx shadcn@latest add \
157 |       "https://ui.stackzero.co/r/${componentName}.json" (Rules: make sure the URL is wrapped in \
158 |       double quotes. Once installed, \
159 |       you can import the component like this: import { ${formatComponentName(
160 |         component.name
161 |       )} } from \
162 |       "@/components/ui/${componentName}";`;
163 | 
164 |       const disclaimerText = `The code below is for context only. It helps you understand
165 |       the component's props, types, and behavior. After installing, the component
166 |       will be available for import via: import { ${formatComponentName(
167 |         component.name
168 |       )} } \
169 |       from "@/components/ui/${componentName}";`;
170 | 
171 |       const exampleDetailsList = await Promise.all(
172 |         relevantExampleNames.map((name) => fetchExampleDetails(name))
173 |       );
174 | 
175 |       const formattedExamples = exampleDetailsList
176 |         .filter((details) => details !== null)
177 |         .map((details) => ({
178 |           name: details.name,
179 |           type: details.type,
180 |           description: details.description,
181 |           content: details.files[0]?.content,
182 |         }));
183 | 
184 |       const validatedComponent = IndividualComponentSchema.parse({
185 |         name: component.name,
186 |         type: component.type,
187 |         description: component.description,
188 |         install: installInstructions,
189 |         content: componentContent && disclaimerText + componentContent,
190 |         examples: formattedExamples,
191 |       });
192 | 
193 |       componentResults.push(validatedComponent);
194 |     } catch (error) {
195 |       console.error(`Error processing component ${componentName}:`, error);
196 |     }
197 |   }
198 | 
199 |   return componentResults;
200 | }
201 | 
202 | /**
203 |  * Fetches blocks by category, processing each block in the category.
204 |  * @param categoryBlocks - The list of block names in the category.
205 |  * @param allBlocks - The complete list of blocks to search from.
206 |  * @returns An array of processed blocks.
207 |  */
208 | async function fetchBlocksByCategory(
209 |   categoryBlocks: string[],
210 |   allBlocks: any[]
211 | ) {
212 |   const blockResults = [];
213 | 
214 |   for (const blockName of categoryBlocks) {
215 |     const block = allBlocks.find((b) => b.name === blockName);
216 |     if (!block) continue;
217 | 
218 |     try {
219 |       const blockDetails = await fetchBlockDetails(blockName);
220 |       const blockContent = blockDetails.files[0]?.content;
221 | 
222 |       // Generate installation instructions
223 |       const installInstructions = `You can install the blocks using  \
224 |       shadcn/ui CLI. For example, with npx: npx shadcn@latest add \
225 |       "https://ui.stackzero.co/r/${blockName}.json" (Rules: make sure the URL is wrapped in \
226 |       double quotes. Once installed, \
227 |       you can import the block like this: import { ${formatComponentName(
228 |         block.name
229 |       )} } from \
230 |       "@/components/ui/${blockName}";`;
231 | 
232 |       const disclaimerText = `The code below is for context only. It helps you understand
233 |       the block's props, types, and behavior. After installing, the block
234 |       will be available for import via: import { ${formatComponentName(
235 |         block.name
236 |       )} } \
237 |       from "@/components/ui/${blockName}";`;
238 | 
239 |       const validatedBlock = IndividualBlockSchema.parse({
240 |         name: block.name,
241 |         type: block.type,
242 |         description: block.description,
243 |         install: installInstructions,
244 |         content: blockContent && disclaimerText + blockContent,
245 |         examples: [], // Blocks typically don't have examples, but can be added if needed
246 |       });
247 | 
248 |       blockResults.push(validatedBlock);
249 |     } catch (error) {
250 |       console.error(`Error processing block ${blockName}:`, error);
251 |     }
252 |   }
253 | 
254 |   return blockResults;
255 | }
256 | 
257 | // Registers tools for each component category
258 | async function registerComponentsCategoryTools() {
259 |   const [components, allExampleComponents] = await Promise.all([
260 |     fetchUIComponents(),
261 |     fetchExampleComponents(),
262 |   ]);
263 | 
264 |   const exampleNamesByComponent =
265 |     createComponentExampleRegistry(allExampleComponents);
266 | 
267 |   // console.error(
268 |   //   "🔍 Found example names by component:",
269 |   //   exampleNamesByComponent
270 |   // );
271 | 
272 |   for (const [category, categoryComponents] of Object.entries(
273 |     componentCategories
274 |   )) {
275 |     const componentNamesString = categoryComponents.join(", ");
276 | 
277 |     server.tool(
278 |       `get${category}`,
279 |       `Provides implementation details for ${componentNamesString} components.`,
280 |       {},
281 |       async () => {
282 |         try {
283 |           const categoryResults = await fetchComponentsByCategory(
284 |             categoryComponents,
285 |             components,
286 |             exampleNamesByComponent
287 |           );
288 | 
289 |           return {
290 |             content: [
291 |               {
292 |                 type: "text",
293 |                 text: JSON.stringify(categoryResults, null, 2),
294 |               },
295 |             ],
296 |           };
297 |         } catch (error) {
298 |           let errorMessage = `Error processing ${category} components`;
299 |           if (error instanceof Error) {
300 |             errorMessage += `: ${error.message}`;
301 |           }
302 |           return {
303 |             content: [{ type: "text", text: errorMessage }],
304 |             isError: true,
305 |           };
306 |         }
307 |       }
308 |     );
309 |   }
310 | }
311 | 
312 | async function registerBlocksCategoryTools() {
313 |   const [blocks] = await Promise.all([fetchUIBlocks()]);
314 | 
315 |   // console.error(
316 |   //   "🔍 Found example names by component:",
317 |   //   exampleNamesByComponent
318 |   // );
319 | 
320 |   for (const [category, categoryBlocks] of Object.entries(blocksCategories)) {
321 |     const blockNamesString = categoryBlocks.join(", ");
322 | 
323 |     server.tool(
324 |       `get${category}`,
325 |       `Provides implementation details for ${blockNamesString} blocks.`,
326 |       {},
327 |       async () => {
328 |         try {
329 |           const categoryResults = await fetchBlocksByCategory(
330 |             categoryBlocks,
331 |             blocks
332 |           );
333 | 
334 |           return {
335 |             content: [
336 |               {
337 |                 type: "text",
338 |                 text: JSON.stringify(categoryResults, null, 2),
339 |               },
340 |             ],
341 |           };
342 |         } catch (error) {
343 |           let errorMessage = `Error processing ${category} blocks`;
344 |           if (error instanceof Error) {
345 |             errorMessage += `: ${error.message}`;
346 |           }
347 |           return {
348 |             content: [{ type: "text", text: errorMessage }],
349 |             isError: true,
350 |           };
351 |         }
352 |       }
353 |     );
354 |   }
355 | }
356 | 
357 | // Start the MCP server
358 | async function startServer() {
359 |   try {
360 |     // Initialize category tools first
361 |     await registerComponentsCategoryTools();
362 |     await registerBlocksCategoryTools();
363 |     // Connect to stdio transport
364 |     const transport = new StdioServerTransport();
365 |     await server.connect(transport);
366 |   } catch (error) {
367 |     console.error("❌ Error starting MCP server:", error);
368 | 
369 |     // Try to start server anyway with basic functionality
370 |     try {
371 |       const transport = new StdioServerTransport();
372 |       await server.connect(transport);
373 |       console.error("⚠️ MCP server started with limited functionality");
374 |     } catch (connectionError) {
375 |       console.error("❌ Failed to connect to transport:", connectionError);
376 |       process.exit(1);
377 |     }
378 |   }
379 | }
380 | 
381 | // Start the server
382 | startServer();
383 | 
```