#
tokens: 6833/50000 15/15 files
lines: off (toggle) GitHub
raw markdown copy
# 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:
--------------------------------------------------------------------------------

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

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

```
.DS_Store
dist/
node_modules/

tsconfig.tsbuildinfo
.husky/_

.env
.env.*

```

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

```
# Source files
src/
tsconfig.json
tsconfig.tsbuildinfo

# Development files
.git/
.gitignore
.DS_Store

# Node modules and lock files
node_modules/
pnpm-lock.yaml
yarn.lock
package-lock.json

# Development and testing
*.log
coverage/
.nyc_output/
.env
.env.local
.env.*.local

# IDE files
.vscode/
.idea/
*.swp
*.swo

# Build artifacts (keep only what's in "files" array)
# Everything else will be excluded by default since we specified "files": ["dist"]

```

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

```markdown
<!-- PROJECT LOGO -->
<br />
<div align="center">
  <a href="https://github.com/stackzero-labs/ui">
    <img src="public/logo.svg" alt="Logo" width="80" height="80">
  </a>

  <h3 align="center">@stackzero-labs/mcp</h3>

  <p align="center">
    Official MCP (Model Context Protocol) server for stackzero-labs/ui.
    <br />
    <a href="https://ui.stackzero.co"><strong>Official Docs »</strong></a>
    <br />
    <br />
    <a href="https://ui.stackzero.co/get-started">Get started</a>
    &middot;
    <a href="https://github.com/stackzero-labs/mcp/issues/new?labels=bug&template=bug-report---.md">Report Bug</a>
    &middot;
    <a href="https://github.com/stackzero-labs/mcp/issues/new?labels=enhancement&template=feature-request---.md">Request Feature</a>
  </p>
</div>

## Overview

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.

## 1-click install in Cursor

[![Install MCP Server](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/install-mcp?name=%40stackzero-labs%2Fmcp&config=eyJjb21tYW5kIjoibnB4IC15IEBzdGFja3plcm8tbGFicy9tY3BAbGF0ZXN0In0%3D)

## Installation

```bash
npm install @stackzero-labs/mcp
```

## Usage

### As a standalone server

```bash
npx @stackzero-labs/mcp
```

### In Claude Desktop

Add to your Claude Desktop configuration:

```json
{
  "mcpServers": {
    "@stackzero-labs/mcp": {
      "command": "npx",
      "args": ["-y", "@stackzero-labs/mcp@latest"]
    }
  }
}
```

### In Cursor (manual setup)

Go to Cursor settings, select `MCP`. Add to your Cursor configuration:

```json
{
  "mcpServers": {
    "@stackzero-labs/mcp": {
      "command": "npx",
      "args": ["-y", "@stackzero-labs/mcp@latest"]
    }
  }
}
```

### Development

```bash
# Install dependencies
pnpm install

# Build the project
pnpm build

# Run in development mode
pnpm dev

# Inspect the MCP server
pnpm inspect
```

## License

See [LICENSE](LICENSE) for details.

```

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

```typescript
export * from "./api.js";
export * from "./formatters.js";
export * from "./schemas.js";

```

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

```typescript
/**
 *  General configuration for MCP service
 */
export const mcpConfig = {
  projectName: "@stackzero-labs/ui",
  baseUrl: "https://ui.stackzero.co",
  registryUrl: "https://ui.stackzero.co/r",
  registryFileUrl: "https://ui.stackzero.co/registry.json",
};

```

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

```typescript
/**
 * Formats a component name by converting it from kebab-case to PascalCase.
 * @param componentName
 * @returns
 */
export function formatComponentName(componentName: string): string {
  return componentName
    .split("-")
    .map((part) => {
      return part.charAt(0).toUpperCase() + part.slice(1);
    })
    .join("");
}

```

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

```json
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ESNext",
    "moduleResolution": "node",
    "outDir": "dist",
    "rootDir": "src",
    "sourceMap": true,
    "declaration": true,
    "strict": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "skipLibCheck": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist"]
}

```

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

```
<svg width="217" height="216" viewBox="0 0 217 216" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1134_83)">
<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"/>
<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"/>
</g>
<defs>
<clipPath id="clip0_1134_83">
<rect width="152.699" height="152.699" fill="white" transform="translate(108.051 215.949) rotate(-135)"/>
</clipPath>
</defs>
</svg>

```

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

```
const Configuration = {
  extends: ["@commitlint/config-conventional"],
  rules: {
    "type-enum": [
      2,
      "always",
      [
        "feat", // A new feature
        "fix", // A bug fix
        "docs", // Documentation only changes
        "style", // Changes that do not affect the meaning of the code
        "refactor", // A code change that neither fixes a bug nor adds a feature
        "perf", // A code change that improves performance
        "test", // Adding missing tests or correcting existing tests
        "chore", // Changes to the build process or auxiliary tools
        "ci", // Changes to CI configuration files and scripts
        "build", // Changes that affect the build system or external dependencies
        "revert", // Reverts a previous commit
      ],
    ],
    "type-case": [2, "always", "lower-case"],
    "type-empty": [2, "never"],
    "scope-case": [2, "always", "lower-case"],
    "subject-case": [
      2,
      "never",
      ["sentence-case", "start-case", "pascal-case", "upper-case"],
    ],
    "subject-empty": [2, "never"],
    "subject-full-stop": [2, "never", "."],
    "header-max-length": [2, "always", 100],
    "body-leading-blank": [1, "always"],
    "body-max-line-length": [2, "always", 100],
    "footer-leading-blank": [1, "always"],
    "footer-max-line-length": [2, "always", 100],
  },
};

export default Configuration;

```

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

```json
{
  "name": "@stackzero-labs/mcp",
  "version": "0.4.0",
  "author": "@stackzero-labs",
  "keywords": [
    "mcp",
    "model-context-protocol",
    "ai",
    "claude",
    "server"
  ],
  "license": "MIT",
  "description": "MCP (Model Context Protocol) server for stackzero-labs/ui",
  "homepage": "https://ui.stackzero.co",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/stackzero-labs/mcp.git"
  },
  "bugs": {
    "url": "https://github.com/stackzero-labs/mcp/issues"
  },
  "scripts": {
    "build": "tsup src/server.ts --format esm,cjs --dts --out-dir dist",
    "build:old": "tsc && shx chmod +x dist/*.js",
    "start": "node dist/server.js",
    "dev": "tsx watch src/server.ts",
    "inspect": "mcp-inspector node dist/server.js",
    "prepublishOnly": "pnpm run build",
    "prepare": "husky"
  },
  "type": "module",
  "main": "./dist/server.js",
  "module": "./dist/server.js",
  "types": "./dist/server.d.ts",
  "bin": {
    "mcp": "./dist/server.js"
  },
  "files": [
    "dist"
  ],
  "dependencies": {
    "@modelcontextprotocol/sdk": "^1.12.3",
    "zod": "^3.25.64"
  },
  "devDependencies": {
    "@commitlint/cli": "^19.8.1",
    "@commitlint/config-conventional": "^19.8.1",
    "@modelcontextprotocol/inspector": "^0.14.2",
    "@types/node": "^22.14.1",
    "husky": "^9.1.7",
    "shx": "^0.4.0",
    "tsup": "^8.5.0",
    "tsx": "^4.20.3",
    "typescript": "^5.8.3"
  }
}

```

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

```typescript
import { z } from "zod";
import { registry } from "zod/dist/types/v4";

export const ComponentSchema = z.object({
  name: z.string(),
  type: z.string(),
  description: z.string().optional(),
});

export const BlockSchema = ComponentSchema.extend({
  name: z.string(),
  type: z.string(),
  description: z.string().optional(),
});

const ExampleSchema = z.object({
  name: z.string(),
  type: z.string(),
  description: z.string(),
  content: z.string(),
});

export const IndividualComponentSchema = ComponentSchema.extend({
  install: z.string(),
  content: z.string(),
  examples: z.array(ExampleSchema),
});

export const IndividualBlockSchema = BlockSchema.extend({
  install: z.string(),
  content: z.string(),
  examples: z.array(ExampleSchema),
});

export const ComponentDetailSchema = z.object({
  name: z.string(),
  type: z.string(),
  files: z.array(
    z.object({
      content: z.string(),
    })
  ),
});

export const BlockDetailSchema = z.object({
  name: z.string(),
  type: z.string(),
  registryDependencies: z.array(z.string()),
  files: z.array(
    z.object({
      content: z.string(),
    })
  ),
});

export const ExampleComponentSchema = z.object({
  name: z.string(),
  type: z.string(),
  description: z.string().optional(),
  registryDependencies: z.array(z.string()),
});

export const ExampleDetailSchema = z.object({
  name: z.string(),
  type: z.string(),
  description: z.string(),
  files: z.array(
    z.object({
      content: z.string(),
    })
  ),
});

```

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

```typescript
// Component category definitions
export const componentCategories = {
  Ratings: [
    "star-rating-basic",
    "star-rating-fractions",
    "upvote-rating-basic",
    "upvote-rating-animated",
    "face-rating-basic",
    "face-rating-gradient",
  ],
  Images: ["image-viewer-basic", "image-viewer-motion", "image-carousel-basic"],
  Products: [
    "price-format-basic",
    "price-format-sale",
    "quantity-input-basic",
    "variant-color-selector-basic",
    "variant-selector-basic",
    "variant-selector-images",
    "variant-selector-multiple",
  ],
  Inputs: ["input-icon", "phone-number-input-basic"],
};

export const blocksCategories = {
  Addresses: ["address-01-block", "address-02-block"],
  Banners: [
    "banner-01-block",
    "banner-02-block",
    "banner-03-block",
    "banner-04-block",
    "banner-05-block",
    "banner-06-block",
    "banner-07-block",
    "banner-08-block",
    "banner-09-block",
    "banner-10-block",
    "banner-11-block",
    "banner-12-block",
  ],
  ProductCards: [
    "product-card-01-block",
    "product-card-02-block",
    "product-card-03-block",
    "product-card-04-block",
    "product-card-05-block",
    "product-card-06-block",
    "product-card-07-block",
    "product-card-08-block",
    "product-card-09-block",
    "product-card-10-block",
    "product-card-11-block",
    "product-card-12-block",
    "product-card-13-block",
  ],
  ProductVariants: [
    "product-variant-01-block",
    "product-variant-02-block",
    "product-variant-03-block",
    "product-variant-04-block",
    "product-variant-05-block",
  ],
  Reviews: [
    "review-01-block",
    "review-02-block",
    "review-03-block",
    "review-04-block",
    "review-05-block",
    "review-06-block",
    "review-07-block",
    "review-08-block",
    "review-09-block",
    "review-10-block",
  ],
  Carts: ["cart-01-block"],
};

```

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

```typescript
import { mcpConfig } from "../lib/config.js";
import {
  BlockDetailSchema,
  BlockSchema,
  ComponentDetailSchema,
  ComponentSchema,
  ExampleComponentSchema,
  ExampleDetailSchema,
} from "./schemas.js";

/**
 *  Fetches all UI components from the registry.
 *  @returns An array of components with their details.
 */
export async function fetchUIComponents() {
  try {
    const response = await fetch(mcpConfig.registryFileUrl);
    if (!response.ok) {
      throw new Error(
        `Failed to fetch registry.json: ${response.statusText} - Status: ${response.status}`
      );
    }
    const data = await response.json();

    return data.registry
      .filter((item: any) => item.type === "registry:component")
      .map((item: any) => {
        try {
          return ComponentSchema.parse({
            name: item.name,
            type: item.type,
            description: item.description,
          });
        } catch (parseError) {
          return null;
        }
      });
  } catch (error) {
    return [];
  }
}

/**
 * Fetches all UI blocks from the registry.
 * @returns An array of UI blocks.
 */
export async function fetchUIBlocks() {
  try {
    const response = await fetch(mcpConfig.registryFileUrl);
    if (!response.ok) {
      throw new Error(
        `Failed to fetch registry.json: ${response.statusText} - Status: ${response.status}`
      );
    }
    const data = await response.json();

    return data.registry
      .filter((item: any) => item.type === "registry:block")
      .map((item: any) => {
        try {
          return BlockSchema.parse({
            name: item.name,
            type: item.type,
            description: item.description,
          });
        } catch (parseError) {
          return null;
        }
      });
  } catch (error) {
    return [];
  }
}

/**
 * Fetches details for a specific component from the registry.
 * @param componentName The name of the component.
 * @returns The details of the component.
 */
export async function fetchComponentDetails(componentName: string) {
  try {
    const response = await fetch(
      `${mcpConfig.registryUrl}/${componentName}.json`
    );
    if (!response.ok) {
      throw new Error(
        `Failed to fetch component ${componentName}: ${response.statusText}`
      );
    }
    const data = await response.json();
    return ComponentDetailSchema.parse(data);
  } catch (error) {
    console.error(`Error fetching component ${componentName}:`, error);
    throw error;
  }
}

/**
 * Fetches details for a specific component from the registry.
 * @param componentName The name of the component.
 * @returns The details of the component.
 */
export async function fetchBlockDetails(blockName: string) {
  try {
    const response = await fetch(`${mcpConfig.registryUrl}/${blockName}.json`);
    if (!response.ok) {
      throw new Error(
        `Failed to fetch block ${blockName}: ${response.statusText}`
      );
    }
    const data = await response.json();
    return BlockDetailSchema.parse(data);
  } catch (error) {
    console.error(`Error fetching block ${blockName}:`, error);
    throw error;
  }
}

/**
 * Fetches example components from the registry.
 * @returns An array of example components.
 */
export async function fetchExampleComponents() {
  try {
    const response = await fetch(mcpConfig.registryFileUrl);
    const data = await response.json();

    return data.registry
      .filter((item: any) => item.type === "registry:example")
      .map((item: any) => {
        return ExampleComponentSchema.parse({
          name: item.name,
          type: item.type,
          description: item.description,
          registryDependencies: item.registryDependencies,
        });
      });
  } catch (error) {
    console.error("Error fetching example components:", error);
    return [];
  }
}

/**
 * Fetches details for a specific example component.
 * @param exampleName The name of the example component.
 * @returns The details of the example component.
 */
export async function fetchExampleDetails(exampleName: string) {
  try {
    const response = await fetch(`${mcpConfig.registryUrl}/${exampleName}`);
    if (!response.ok) {
      throw new Error(
        `Failed to fetch example details for ${exampleName}: ${response.statusText}`
      );
    }
    const data = await response.json();
    return ExampleDetailSchema.parse(data);
  } catch (error) {
    console.error(`Error fetching example details for ${exampleName}:`, error);
    throw error;
  }
}

```

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

```typescript
#!/usr/bin/env node

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
  IndividualComponentSchema,
  fetchComponentDetails,
  fetchBlockDetails,
  fetchExampleComponents,
  fetchExampleDetails,
  fetchUIBlocks,
  fetchUIComponents,
  IndividualBlockSchema,
} from "./utils/index.js";
import { formatComponentName } from "./utils/formatters.js";
import { blocksCategories, componentCategories } from "./lib/categories.js";

// Initialize the MCP Server
const server = new McpServer({
  name: "@stackzero-labs/mcp",
  version: "0.2.0",
});

// Register the main tool for getting all components
server.tool(
  "getUIComponents",
  "Provides a comprehensive list of all stackzero-labs/ui components.",
  {},
  async () => {
    try {
      const uiComponents = await fetchUIComponents();

      return {
        content: [
          {
            type: "text",
            text: JSON.stringify(uiComponents, null, 2),
          },
        ],
      };
    } catch (error) {
      return {
        content: [
          {
            type: "text",
            text: "Failed to fetch stackzero-labs/ui components",
          },
        ],
        isError: true,
      };
    }
  }
);

// Register the main tool for getting all blocks
server.tool(
  "getUIBlocks",
  "Provides a comprehensive list of all stackzero-labs/ui blocks.",
  {},
  async () => {
    try {
      const uiBlocks = await fetchUIBlocks();
      return {
        content: [
          {
            type: "text",
            text: JSON.stringify(uiBlocks, null, 2),
          },
        ],
      };
    } catch (error) {
      return {
        content: [
          {
            type: "text",
            text: "Failed to fetch stackzero-labs/ui blocks",
          },
        ],
      };
    }
  }
);

/**
 * Creates a registry mapping component names to their example implementations.
 * @param exampleComponentList - The list of example components to process.
 * @returns A map where each key is a component name and the value is an array of example names.
 */
function createComponentExampleRegistry(
  exampleComponentList: Array<{
    name: string;
    registryDependencies?: string[];
  }>
): Map<string, string[]> {
  const componentRegistry = new Map<string, string[]>();

  for (const exampleItem of exampleComponentList) {
    if (
      exampleItem.registryDependencies &&
      Array.isArray(exampleItem.registryDependencies)
    ) {
      for (const dependencyUrl of exampleItem.registryDependencies) {
        if (
          typeof dependencyUrl === "string" &&
          dependencyUrl.includes("stackzero.co")
        ) {
          const nameExtraction = dependencyUrl.match(/\/r\/([^\/]+)$/);
          if (nameExtraction && nameExtraction[1]) {
            const extractedComponentName = nameExtraction[1];
            if (!componentRegistry.has(extractedComponentName)) {
              componentRegistry.set(extractedComponentName, []);
            }
            if (
              !componentRegistry
                .get(extractedComponentName)
                ?.includes(exampleItem.name)
            ) {
              componentRegistry
                .get(extractedComponentName)
                ?.push(exampleItem.name);
            }
          }
        }
      }
    }
  }
  return componentRegistry;
}

/**
 * Fetches components and blocks by category, processing each category's components and blocks.
 * @param categoryComponents - The list of component names in the category.
 * @param categoryBlocks - The list of block names in the category.
 * @returns An object containing the processed components and blocks.
 */
async function fetchComponentsByCategory(
  categoryComponents: string[],
  allComponents: any[],
  exampleNamesByComponent: Map<string, string[]>
) {
  const componentResults = [];

  for (const componentName of categoryComponents) {
    const component = allComponents.find((c) => c.name === componentName);
    if (!component) continue;

    try {
      const componentDetails = await fetchComponentDetails(componentName);
      const componentContent = componentDetails.files[0]?.content;

      const relevantExampleNames =
        exampleNamesByComponent.get(componentName) || [];

      // Generate installation instructions
      const installInstructions = `You can install the component/blocks using  \
      shadcn/ui CLI. For example, with npx: npx shadcn@latest add \
      "https://ui.stackzero.co/r/${componentName}.json" (Rules: make sure the URL is wrapped in \
      double quotes. Once installed, \
      you can import the component like this: import { ${formatComponentName(
        component.name
      )} } from \
      "@/components/ui/${componentName}";`;

      const disclaimerText = `The code below is for context only. It helps you understand
      the component's props, types, and behavior. After installing, the component
      will be available for import via: import { ${formatComponentName(
        component.name
      )} } \
      from "@/components/ui/${componentName}";`;

      const exampleDetailsList = await Promise.all(
        relevantExampleNames.map((name) => fetchExampleDetails(name))
      );

      const formattedExamples = exampleDetailsList
        .filter((details) => details !== null)
        .map((details) => ({
          name: details.name,
          type: details.type,
          description: details.description,
          content: details.files[0]?.content,
        }));

      const validatedComponent = IndividualComponentSchema.parse({
        name: component.name,
        type: component.type,
        description: component.description,
        install: installInstructions,
        content: componentContent && disclaimerText + componentContent,
        examples: formattedExamples,
      });

      componentResults.push(validatedComponent);
    } catch (error) {
      console.error(`Error processing component ${componentName}:`, error);
    }
  }

  return componentResults;
}

/**
 * Fetches blocks by category, processing each block in the category.
 * @param categoryBlocks - The list of block names in the category.
 * @param allBlocks - The complete list of blocks to search from.
 * @returns An array of processed blocks.
 */
async function fetchBlocksByCategory(
  categoryBlocks: string[],
  allBlocks: any[]
) {
  const blockResults = [];

  for (const blockName of categoryBlocks) {
    const block = allBlocks.find((b) => b.name === blockName);
    if (!block) continue;

    try {
      const blockDetails = await fetchBlockDetails(blockName);
      const blockContent = blockDetails.files[0]?.content;

      // Generate installation instructions
      const installInstructions = `You can install the blocks using  \
      shadcn/ui CLI. For example, with npx: npx shadcn@latest add \
      "https://ui.stackzero.co/r/${blockName}.json" (Rules: make sure the URL is wrapped in \
      double quotes. Once installed, \
      you can import the block like this: import { ${formatComponentName(
        block.name
      )} } from \
      "@/components/ui/${blockName}";`;

      const disclaimerText = `The code below is for context only. It helps you understand
      the block's props, types, and behavior. After installing, the block
      will be available for import via: import { ${formatComponentName(
        block.name
      )} } \
      from "@/components/ui/${blockName}";`;

      const validatedBlock = IndividualBlockSchema.parse({
        name: block.name,
        type: block.type,
        description: block.description,
        install: installInstructions,
        content: blockContent && disclaimerText + blockContent,
        examples: [], // Blocks typically don't have examples, but can be added if needed
      });

      blockResults.push(validatedBlock);
    } catch (error) {
      console.error(`Error processing block ${blockName}:`, error);
    }
  }

  return blockResults;
}

// Registers tools for each component category
async function registerComponentsCategoryTools() {
  const [components, allExampleComponents] = await Promise.all([
    fetchUIComponents(),
    fetchExampleComponents(),
  ]);

  const exampleNamesByComponent =
    createComponentExampleRegistry(allExampleComponents);

  // console.error(
  //   "🔍 Found example names by component:",
  //   exampleNamesByComponent
  // );

  for (const [category, categoryComponents] of Object.entries(
    componentCategories
  )) {
    const componentNamesString = categoryComponents.join(", ");

    server.tool(
      `get${category}`,
      `Provides implementation details for ${componentNamesString} components.`,
      {},
      async () => {
        try {
          const categoryResults = await fetchComponentsByCategory(
            categoryComponents,
            components,
            exampleNamesByComponent
          );

          return {
            content: [
              {
                type: "text",
                text: JSON.stringify(categoryResults, null, 2),
              },
            ],
          };
        } catch (error) {
          let errorMessage = `Error processing ${category} components`;
          if (error instanceof Error) {
            errorMessage += `: ${error.message}`;
          }
          return {
            content: [{ type: "text", text: errorMessage }],
            isError: true,
          };
        }
      }
    );
  }
}

async function registerBlocksCategoryTools() {
  const [blocks] = await Promise.all([fetchUIBlocks()]);

  // console.error(
  //   "🔍 Found example names by component:",
  //   exampleNamesByComponent
  // );

  for (const [category, categoryBlocks] of Object.entries(blocksCategories)) {
    const blockNamesString = categoryBlocks.join(", ");

    server.tool(
      `get${category}`,
      `Provides implementation details for ${blockNamesString} blocks.`,
      {},
      async () => {
        try {
          const categoryResults = await fetchBlocksByCategory(
            categoryBlocks,
            blocks
          );

          return {
            content: [
              {
                type: "text",
                text: JSON.stringify(categoryResults, null, 2),
              },
            ],
          };
        } catch (error) {
          let errorMessage = `Error processing ${category} blocks`;
          if (error instanceof Error) {
            errorMessage += `: ${error.message}`;
          }
          return {
            content: [{ type: "text", text: errorMessage }],
            isError: true,
          };
        }
      }
    );
  }
}

// Start the MCP server
async function startServer() {
  try {
    // Initialize category tools first
    await registerComponentsCategoryTools();
    await registerBlocksCategoryTools();
    // Connect to stdio transport
    const transport = new StdioServerTransport();
    await server.connect(transport);
  } catch (error) {
    console.error("❌ Error starting MCP server:", error);

    // Try to start server anyway with basic functionality
    try {
      const transport = new StdioServerTransport();
      await server.connect(transport);
      console.error("⚠️ MCP server started with limited functionality");
    } catch (connectionError) {
      console.error("❌ Failed to connect to transport:", connectionError);
      process.exit(1);
    }
  }
}

// Start the server
startServer();

```