# Directory Structure
```
├── .gitignore
├── LICENSE.md
├── package-lock.json
├── package.json
├── public
│ └── mcp.png
├── README.md
├── src
│ ├── server.ts
│ └── utils
│ ├── api.ts
│ ├── formatters.ts
│ ├── index.ts
│ └── schemas.ts
└── tsconfig.json
```
# Files
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
```
1 | node_modules/
2 | .DS_Store
3 | dist/
4 | tsconfig.tsbuildinfo
```
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
```markdown
1 | # @magicuidesign/mcp
2 |
3 | [](https://badge.fury.io/js/@magicuidesign%2Fmcp)
4 |
5 | Official ModelContextProtocol (MCP) server for [Magic UI](https://magicui.design/).
6 |
7 | <div align="center">
8 | <img src="https://github.com/magicuidesign/mcp/blob/main/public/mcp.png" alt="MCP" />
9 | </div>
10 |
11 | ## Install MCP configuration
12 |
13 | ```bash
14 | npx @magicuidesign/cli@latest install <client>
15 | ```
16 |
17 | ### Supported Clients
18 |
19 | - [x] cursor
20 | - [x] windsurf
21 | - [x] claude
22 | - [x] cline
23 | - [x] roo-cline
24 |
25 | ## Manual Installation
26 |
27 | Add to your IDE's MCP config:
28 |
29 | ```json
30 | {
31 | "mcpServers": {
32 | "@magicuidesign/mcp": {
33 | "command": "npx",
34 | "args": ["-y", "@magicuidesign/mcp@latest"]
35 | }
36 | }
37 | }
38 | ```
39 |
40 | ## Example Usage
41 |
42 | Once configured, you can questions like:
43 |
44 | > "Make a marquee of logos"
45 |
46 | > "Add a blur fade text animation"
47 |
48 | > "Add a grid background"
49 |
50 | ## Available Tools
51 |
52 | The server provides the following tools callable via MCP:
53 |
54 | | Tool Name | Description |
55 | |-----------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
56 | | `getUIComponents` | Provides a comprehensive list of all Magic UI components. |
57 | | `getLayout` | Provides implementation details for [bento-grid](https://magicui.design/docs/components/bento-grid), [dock](https://magicui.design/docs/components/dock), [file-tree](https://magicui.design/docs/components/file-tree), [grid-pattern](https://magicui.design/docs/components/grid-pattern), [interactive-grid-pattern](https://magicui.design/docs/components/interactive-grid-pattern), [dot-pattern](https://magicui.design/docs/components/dot-pattern) components. |
58 | | `getMedia` | Provides implementation details for [hero-video-dialog](https://magicui.design/docs/components/hero-video-dialog), [terminal](https://magicui.design/docs/components/terminal), [marquee](https://magicui.design/docs/components/marquee), [script-copy-btn](https://magicui.design/docs/components/script-copy-btn), [code-comparison](https://magicui.design/docs/components/code-comparison) components. |
59 | | `getMotion` | Provides implementation details for [blur-fade](https://magicui.design/docs/components/blur-fade), [scroll-progress](https://magicui.design/docs/components/scroll-progress), [scroll-based-velocity](https://magicui.design/docs/components/scroll-based-velocity), [orbiting-circles](https://magicui.design/docs/components/orbiting-circles), [animated-circular-progress-bar](https://magicui.design/docs/components/animated-circular-progress-bar) components. |
60 | | `getTextReveal` | Provides implementation details for [text-animate](https://magicui.design/docs/components/text-animate), [line-shadow-text](https://magicui.design/docs/components/line-shadow-text), [aurora-text](https://magicui.design/docs/components/aurora-text), [animated-shiny-text](https://magicui.design/docs/components/animated-shiny-text), [animated-gradient-text](https://magicui.design/docs/components/animated-gradient-text), [text-reveal](https://magicui.design/docs/components/text-reveal), [typing-animation](https://magicui.design/docs/components/typing-animation), [box-reveal](https://magicui.design/docs/components/box-reveal), [number-ticker](https://magicui.design/docs/components/number-ticker) components. |
61 | | `getTextEffects` | Provides implementation details for [word-rotate](https://magicui.design/docs/components/word-rotate), [flip-text](https://magicui.design/docs/components/flip-text), [hyper-text](https://magicui.design/docs/components/hyper-text), [morphing-text](https://magicui.design/docs/components/morphing-text), [spinning-text](https://magicui.design/docs/components/spinning-text), [sparkles-text](https://magicui.design/docs/components/sparkles-text) components. |
62 | | `getButtons` | Provides implementation details for [rainbow-button](https://magicui.design/docs/components/rainbow-button), [shimmer-button](https://magicui.design/docs/components/shimmer-button), [shiny-button](https://magicui.design/docs/components/shiny-button), [interactive-hover-button](https://magicui.design/docs/components/interactive-hover-button), [animated-subscribe-button](https://magicui.design/docs/components/animated-subscribe-button), [pulsating-button](https://magicui.design/docs/components/pulsating-button), [ripple-button](https://magicui.design/docs/components/ripple-button) components. |
63 | | `getEffects` | Provides implementation details for [animated-beam](https://magicui.design/docs/components/animated-beam), [border-beam](https://magicui.design/docs/components/border-beam), [shine-border](https://magicui.design/docs/components/shine-border), [magic-card](https://magicui.design/docs/components/magic-card), [meteors](https://magicui.design/docs/components/meteors), [neon-gradient-card](https://magicui.design/docs/components/neon-gradient-card), [confetti](https://magicui.design/docs/components/confetti), [particles](https://magicui.design/docs/components/particles), [cool-mode](https://magicui.design/docs/components/cool-mode), [scratch-to-reveal](https://magicui.design/docs/components/scratch-to-reveal) components. |
64 | | `getWidgets` | Provides implementation details for [animated-list](https://magicui.design/docs/components/animated-list), [tweet-card](https://magicui.design/docs/components/tweet-card), [client-tweet-card](https://magicui.design/docs/components/client-tweet-card), [lens](https://magicui.design/docs/components/lens), [pointer](https://magicui.design/docs/components/pointer), [avatar-circles](https://magicui.design/docs/components/avatar-circles), [icon-cloud](https://magicui.design/docs/components/icon-cloud), [globe](https://magicui.design/docs/components/globe) components. |
65 | | `getBackgrounds` | Provides implementation details for [warp-background](https://magicui.design/docs/components/warp-background), [flickering-grid](https://magicui.design/docs/components/flickering-grid), [animated-grid-pattern](https://magicui.design/docs/components/animated-grid-pattern), [retro-grid](https://magicui.design/docs/components/retro-grid), [ripple](https://magicui.design/docs/components/ripple) components. |
66 | | `getDevices` | Provides implementation details for [safari](https://magicui.design/docs/components/safari), [iphone-15-pro](https://magicui.design/docs/components/iphone-15-pro), [android](https://magicui.design/docs/components/android) components. |
67 |
68 | ## MCP Limitations
69 |
70 | Some clients have a [limit](https://docs.cursor.com/context/model-context-protocol#limitations) on the number of tools they can call. This is why we opted to group the tools into categories. Note: For more specific context on each component, run the MCP locally and modify the logic that groups the components.
71 |
72 | ## Credits
73 |
74 | Big thanks to [@beaubhp](https://github.com/beaubhp) for creating the MCP server 🙏
75 |
76 | [MIT](https://github.com/magicuidesign/mcp/blob/main/LICENSE.md)
```
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
```markdown
1 | MIT License
2 |
3 | Copyright (c) Magic UI
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
```
--------------------------------------------------------------------------------
/src/utils/index.ts:
--------------------------------------------------------------------------------
```typescript
1 | export * from "./api.js";
2 | export * from "./formatters.js";
3 | export * from "./schemas.js";
4 |
```
--------------------------------------------------------------------------------
/src/utils/formatters.ts:
--------------------------------------------------------------------------------
```typescript
1 | // Helper function to format component names
2 | export function formatComponentName(name: string): string {
3 | return name
4 | .split("-")
5 | .map((part) => {
6 | return part.charAt(0).toUpperCase() + part.slice(1);
7 | })
8 | .join("");
9 | }
10 |
```
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "compilerOptions": {
3 | "baseUrl": ".",
4 | "esModuleInterop": true,
5 | "skipLibCheck": true,
6 | "target": "ES2022",
7 | "allowJs": true,
8 | "resolveJsonModule": true,
9 | "moduleDetection": "force",
10 | "isolatedModules": true,
11 | "strict": true,
12 | "noUncheckedIndexedAccess": true,
13 | "noImplicitAny": true,
14 | "module": "esnext",
15 | "moduleResolution": "bundler",
16 | "outDir": "dist",
17 | "rootDir": "src",
18 | "sourceMap": true,
19 | "declaration": true,
20 | "incremental": true,
21 | },
22 | "include": ["**/*.ts"],
23 | "exclude": ["node_modules", "dist"]
24 | }
```
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "name": "@magicuidesign/mcp",
3 | "version": "1.0.6",
4 | "description": "Official MCP server for Magic UI.",
5 | "homepage": "https://magicui.design",
6 | "repository": {
7 | "type": "git",
8 | "url": "git+https://github.com/magicuidesign/mcp.git"
9 | },
10 | "scripts": {
11 | "build": "tsc && shx chmod +x dist/*.js",
12 | "start": "node dist/server.js",
13 | "dev": "nodemon --watch src --ext ts,json --exec \"npm run build\""
14 | },
15 | "type": "module",
16 | "main": "./dist/server.js",
17 | "module": "./dist/server.js",
18 | "types": "./dist/server.d.ts",
19 | "bin": {
20 | "mcp": "./dist/server.js"
21 | },
22 | "files": [
23 | "dist"
24 | ],
25 | "dependencies": {
26 | "@modelcontextprotocol/sdk": "^1.9.0",
27 | "zod": "^3.24.2"
28 | },
29 | "devDependencies": {
30 | "@types/node": "^22.14.1",
31 | "nodemon": "^3.1.0",
32 | "shx": "^0.4.0",
33 | "typescript": "^5.8.3"
34 | },
35 | "author": "Beau Hayes-Pollard <[email protected]>",
36 | "license": "ISC"
37 | }
38 |
```
--------------------------------------------------------------------------------
/src/utils/schemas.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { z } from "zod";
2 |
3 | // Define schema for general component
4 | export const ComponentSchema = z.object({
5 | name: z.string(),
6 | type: z.string(),
7 | description: z.string().optional(), // Only optional because of interactive-hover-button
8 | });
9 |
10 | // Define schema for an individual example
11 | const ExampleSchema = z.object({
12 | name: z.string(),
13 | type: z.string(),
14 | description: z.string(),
15 | content: z.string(),
16 | });
17 |
18 | // Define schema for individual component with content and examples
19 | export const IndividualComponentSchema = ComponentSchema.extend({
20 | install: z.string(),
21 | content: z.string(),
22 | examples: z.array(ExampleSchema),
23 | });
24 |
25 | // Define schema for component detail response
26 | export const ComponentDetailSchema = z.object({
27 | name: z.string(),
28 | type: z.string(),
29 | files: z.array(
30 | z.object({
31 | content: z.string(),
32 | }),
33 | ),
34 | });
35 |
36 | // Define schema for example component
37 | export const ExampleComponentSchema = z.object({
38 | name: z.string(),
39 | type: z.string(),
40 | description: z.string(),
41 | registryDependencies: z.array(z.string()),
42 | });
43 |
44 | // Define schema for example detail response
45 | export const ExampleDetailSchema = z.object({
46 | name: z.string(),
47 | type: z.string(),
48 | description: z.string(),
49 | files: z.array(
50 | z.object({
51 | content: z.string(),
52 | }),
53 | ),
54 | });
55 |
```
--------------------------------------------------------------------------------
/src/utils/api.ts:
--------------------------------------------------------------------------------
```typescript
1 | import {
2 | ComponentDetailSchema,
3 | ComponentSchema,
4 | ExampleComponentSchema,
5 | ExampleDetailSchema,
6 | } from "./schemas.js";
7 |
8 | // Function to fetch UI components
9 | export async function fetchUIComponents() {
10 | try {
11 | const response = await fetch("https://magicui.design/registry.json");
12 | if (!response.ok) {
13 | throw new Error(
14 | `Failed to fetch registry.json: ${response.statusText} (Status: ${response.status})`,
15 | );
16 | }
17 | const data = await response.json();
18 |
19 | return data.items
20 | .filter((item: any) => item.type === "registry:ui")
21 | .map((item: any) => {
22 | try {
23 | return ComponentSchema.parse({
24 | name: item.name,
25 | type: item.type,
26 | description: item.description,
27 | });
28 | } catch (parseError) {
29 | return null;
30 | }
31 | });
32 | } catch (error) {
33 | return [];
34 | }
35 | }
36 |
37 | // Function to fetch individual component details
38 | export async function fetchComponentDetails(name: string) {
39 | try {
40 | const response = await fetch(`https://magicui.design/r/${name}`);
41 | if (!response.ok) {
42 | throw new Error(
43 | `Failed to fetch component ${name}: ${response.statusText}`,
44 | );
45 | }
46 | const data = await response.json();
47 | return ComponentDetailSchema.parse(data);
48 | } catch (error) {
49 | console.error(`Error fetching component ${name}:`, error);
50 | throw error;
51 | }
52 | }
53 |
54 | // Function to fetch example components
55 | export async function fetchExampleComponents() {
56 | try {
57 | const response = await fetch("https://magicui.design/registry.json");
58 | const data = await response.json();
59 |
60 | return data.items
61 | .filter((item: any) => item.type === "registry:example")
62 | .map((item: any) => {
63 | return ExampleComponentSchema.parse({
64 | name: item.name,
65 | type: item.type,
66 | description: item.description,
67 | registryDependencies: item.registryDependencies,
68 | });
69 | });
70 | } catch (error) {
71 | console.error("Error fetching MagicUI example components:", error);
72 | return [];
73 | }
74 | }
75 |
76 | // Function to fetch details for a specific example
77 | export async function fetchExampleDetails(exampleName: string) {
78 | try {
79 | const response = await fetch(`https://magicui.design/r/${exampleName}`);
80 | if (!response.ok) {
81 | throw new Error(
82 | `Failed to fetch example details for ${exampleName}: ${response.statusText}`,
83 | );
84 | }
85 | const data = await response.json();
86 | return ExampleDetailSchema.parse(data);
87 | } catch (error) {
88 | console.error(`Error fetching example details for ${exampleName}:`, error);
89 | throw error;
90 | }
91 | }
92 |
```
--------------------------------------------------------------------------------
/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 | fetchExampleComponents,
9 | fetchExampleDetails,
10 | fetchUIComponents,
11 | } from "./utils/index.js";
12 | import { formatComponentName } from "./utils/formatters.js";
13 |
14 | // Initialize the MCP Server
15 | const server = new McpServer({
16 | name: "Magic UI MCP",
17 | version: "1.0.4",
18 | });
19 |
20 | // Register the main tool for getting all components
21 | server.tool(
22 | "getUIComponents",
23 | "Provides a comprehensive list of all Magic UI components.",
24 | {},
25 | async () => {
26 | try {
27 | const uiComponents = await fetchUIComponents();
28 |
29 | return {
30 | content: [
31 | {
32 | type: "text",
33 | text: JSON.stringify(uiComponents, null, 2),
34 | },
35 | ],
36 | };
37 | } catch (error) {
38 | return {
39 | content: [
40 | {
41 | type: "text",
42 | text: "Failed to fetch MagicUI components",
43 | },
44 | ],
45 | isError: true,
46 | };
47 | }
48 | },
49 | );
50 |
51 | // Maps component names to their example implementations
52 | function buildExampleComponentMap(
53 | allExampleComponents: Array<{
54 | name: string;
55 | registryDependencies?: string[];
56 | }>,
57 | ): Map<string, string[]> {
58 | const exampleMap = new Map<string, string[]>();
59 |
60 | for (const example of allExampleComponents) {
61 | if (
62 | example.registryDependencies &&
63 | Array.isArray(example.registryDependencies)
64 | ) {
65 | for (const depUrl of example.registryDependencies) {
66 | if (typeof depUrl === "string" && depUrl.includes("magicui.design")) {
67 | const componentNameMatch = depUrl.match(/\/r\/([^\/]+)$/);
68 | if (componentNameMatch && componentNameMatch[1]) {
69 | const componentName = componentNameMatch[1];
70 | if (!exampleMap.has(componentName)) {
71 | exampleMap.set(componentName, []);
72 | }
73 | if (!exampleMap.get(componentName)?.includes(example.name)) {
74 | exampleMap.get(componentName)?.push(example.name);
75 | }
76 | }
77 | }
78 | }
79 | }
80 | }
81 | return exampleMap;
82 | }
83 |
84 | // Component category definitions
85 | const componentCategories = {
86 | Layout: [
87 | "bento-grid",
88 | "dock",
89 | "file-tree",
90 | "grid-pattern",
91 | "interactive-grid-pattern",
92 | "dot-pattern",
93 | ],
94 | Media: [
95 | "hero-video-dialog",
96 | "terminal",
97 | "marquee",
98 | "script-copy-btn",
99 | "code-comparison",
100 | ],
101 | Motion: [
102 | "blur-fade",
103 | "scroll-progress",
104 | "scroll-based-velocity",
105 | "orbiting-circles",
106 | "animated-circular-progress-bar",
107 | ],
108 | TextReveal: [
109 | "text-animate",
110 | "line-shadow-text",
111 | "aurora-text",
112 | "animated-shiny-text",
113 | "animated-gradient-text",
114 | "text-reveal",
115 | "typing-animation",
116 | "box-reveal",
117 | "number-ticker",
118 | ],
119 | TextEffects: [
120 | "word-rotate",
121 | "flip-text",
122 | "hyper-text",
123 | "morphing-text",
124 | "spinning-text",
125 | "sparkles-text",
126 | ],
127 | Buttons: [
128 | "rainbow-button",
129 | "shimmer-button",
130 | "shiny-button",
131 | "interactive-hover-button",
132 | "animated-subscribe-button",
133 | "pulsating-button",
134 | "ripple-button",
135 | ],
136 | Effects: [
137 | "animated-beam",
138 | "border-beam",
139 | "shine-border",
140 | "magic-card",
141 | "meteors",
142 | "neon-gradient-card",
143 | "confetti",
144 | "particles",
145 | "cool-mode",
146 | "scratch-to-reveal",
147 | ],
148 | Widgets: [
149 | "animated-list",
150 | "tweet-card",
151 | "client-tweet-card",
152 | "lens",
153 | "pointer",
154 | "avatar-circles",
155 | "icon-cloud",
156 | "globe",
157 | ],
158 | Backgrounds: [
159 | "warp-background",
160 | "flickering-grid",
161 | "animated-grid-pattern",
162 | "retro-grid",
163 | "ripple",
164 | ],
165 | Devices: [
166 | "safari",
167 | "iphone-15-pro",
168 | "android",
169 | ],
170 | };
171 |
172 | // Fetches detailed information about components in a specific category
173 | async function fetchComponentsByCategory(
174 | categoryComponents: string[],
175 | allComponents: any[],
176 | exampleNamesByComponent: Map<string, string[]>,
177 | ) {
178 | const componentResults = [];
179 |
180 | for (const componentName of categoryComponents) {
181 | const component = allComponents.find((c) => c.name === componentName);
182 | if (!component) continue;
183 |
184 | try {
185 | const componentDetails = await fetchComponentDetails(componentName);
186 | const componentContent = componentDetails.files[0]?.content;
187 |
188 | const relevantExampleNames =
189 | exampleNamesByComponent.get(componentName) || [];
190 |
191 | // Generate installation instructions
192 | const installInstructions = `Install the component using the same process as \
193 | shadcn/ui. If you run into linter or dependency errors, make sure to install the \
194 | component using these instructions. For example, with npm/npx: npx shadcn@latest add \
195 | "https://magicui.design/r/${componentName}.json" (Rules: make sure the URL is wrapped in \
196 | double quotes and use shadcn not shadcn-ui, or the command will fail). After installation, \
197 | you can import the component like this: import { ${formatComponentName(component.name)} } from \
198 | "@/components/ui/${componentName}";`;
199 |
200 | const disclaimerText = `The code below is for context only. It helps you understand \
201 | the component's props, types, and behavior. To actually install and use the \
202 | component, refer to the install instructions above. After installing, the component \
203 | will be available for import via: import { ${formatComponentName(component.name)} } \
204 | from "@/components/ui/${componentName}";`;
205 |
206 | const exampleDetailsList = await Promise.all(
207 | relevantExampleNames.map((name) => fetchExampleDetails(name)),
208 | );
209 |
210 | const formattedExamples = exampleDetailsList
211 | .filter((details) => details !== null)
212 | .map((details) => ({
213 | name: details.name,
214 | type: details.type,
215 | description: details.description,
216 | content: details.files[0]?.content,
217 | }));
218 |
219 | const validatedComponent = IndividualComponentSchema.parse({
220 | name: component.name,
221 | type: component.type,
222 | description: component.description,
223 | install: installInstructions,
224 | content: componentContent && disclaimerText + componentContent,
225 | examples: formattedExamples,
226 | });
227 |
228 | componentResults.push(validatedComponent);
229 | } catch (error) {
230 | console.error(`Error processing component ${componentName}:`, error);
231 | }
232 | }
233 |
234 | return componentResults;
235 | }
236 |
237 | // Registers tools for each component category
238 | async function registerCategoryTools() {
239 | const [components, allExampleComponents] = await Promise.all([
240 | fetchUIComponents(),
241 | fetchExampleComponents(),
242 | ]);
243 |
244 | const exampleNamesByComponent =
245 | buildExampleComponentMap(allExampleComponents);
246 |
247 | for (const [category, categoryComponents] of Object.entries(
248 | componentCategories,
249 | )) {
250 | const componentNamesString = categoryComponents.join(", ");
251 |
252 | server.tool(
253 | `get${category}`,
254 | `Provides implementation details for ${componentNamesString} components.`,
255 | {},
256 | async () => {
257 | try {
258 | const categoryResults = await fetchComponentsByCategory(
259 | categoryComponents,
260 | components,
261 | exampleNamesByComponent,
262 | );
263 |
264 | return {
265 | content: [
266 | {
267 | type: "text",
268 | text: JSON.stringify(categoryResults, null, 2),
269 | },
270 | ],
271 | };
272 | } catch (error) {
273 | let errorMessage = `Error processing ${category} components`;
274 | if (error instanceof Error) {
275 | errorMessage += `: ${error.message}`;
276 | }
277 | return {
278 | content: [{ type: "text", text: errorMessage }],
279 | isError: true,
280 | };
281 | }
282 | },
283 | );
284 | }
285 | }
286 |
287 | // Initialize category tools before starting the server
288 | registerCategoryTools()
289 | .then(() => {
290 | const transport = new StdioServerTransport();
291 | server.connect(transport);
292 | })
293 | .catch((error) => {
294 | console.error("Error registering category tools:", error);
295 | const transport = new StdioServerTransport();
296 | server.connect(transport);
297 | });
```