archyra 1.0.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/mcp/server.ts ADDED
@@ -0,0 +1,363 @@
1
+ /**
2
+ * Archyra - MCP Server
3
+ *
4
+ * Model Context Protocol server that allows AI assistants to:
5
+ * - List available animation components
6
+ * - Get component details and documentation
7
+ * - Add components to user projects
8
+ */
9
+
10
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
11
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
12
+ import {
13
+ CallToolRequestSchema,
14
+ ListToolsRequestSchema,
15
+ } from '@modelcontextprotocol/sdk/types.js';
16
+ import { components, getComponent, listComponents, getCategories, ComponentInfo } from './registry.js';
17
+ import * as fs from 'fs';
18
+ import * as path from 'path';
19
+
20
+ const server = new Server(
21
+ {
22
+ name: 'archyra',
23
+ version: '1.0.0',
24
+ },
25
+ {
26
+ capabilities: {
27
+ tools: {},
28
+ },
29
+ }
30
+ );
31
+
32
+ // List available tools
33
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
34
+ return {
35
+ tools: [
36
+ {
37
+ name: 'list_components',
38
+ description: 'List all available AI animation components. Optionally filter by category.',
39
+ inputSchema: {
40
+ type: 'object',
41
+ properties: {
42
+ category: {
43
+ type: 'string',
44
+ description: 'Filter by category: loading, processing, creative, auth, chat, ecommerce, or all',
45
+ enum: ['all', 'loading', 'processing', 'creative', 'auth', 'chat', 'ecommerce'],
46
+ },
47
+ },
48
+ },
49
+ },
50
+ {
51
+ name: 'get_component',
52
+ description: 'Get detailed information about a specific component including props, usage example, and source code. Supports React and vanilla HTML/CSS formats.',
53
+ inputSchema: {
54
+ type: 'object',
55
+ properties: {
56
+ name: {
57
+ type: 'string',
58
+ description: 'Component name or ID (e.g., "LoadingDots", "loading-dots", "PulseCircle")',
59
+ },
60
+ format: {
61
+ type: 'string',
62
+ description: 'Output format: "react" for React/Framer Motion, "vanilla" for plain HTML/CSS/JS',
63
+ enum: ['react', 'vanilla'],
64
+ },
65
+ },
66
+ required: ['name'],
67
+ },
68
+ },
69
+ {
70
+ name: 'add_component',
71
+ description: 'Add an animation component to the user\'s project. Supports React (.tsx) and vanilla HTML/CSS/JS formats.',
72
+ inputSchema: {
73
+ type: 'object',
74
+ properties: {
75
+ name: {
76
+ type: 'string',
77
+ description: 'Component name or ID to add',
78
+ },
79
+ directory: {
80
+ type: 'string',
81
+ description: 'Directory path where to create the component (default: ./components)',
82
+ },
83
+ format: {
84
+ type: 'string',
85
+ description: 'Output format: "react" (default) or "vanilla" for plain HTML/CSS/JS',
86
+ enum: ['react', 'vanilla'],
87
+ },
88
+ },
89
+ required: ['name'],
90
+ },
91
+ },
92
+ {
93
+ name: 'get_install_command',
94
+ description: 'Get the npm install command for required dependencies of a component.',
95
+ inputSchema: {
96
+ type: 'object',
97
+ properties: {
98
+ name: {
99
+ type: 'string',
100
+ description: 'Component name or ID',
101
+ },
102
+ },
103
+ required: ['name'],
104
+ },
105
+ },
106
+ ],
107
+ };
108
+ });
109
+
110
+ // Handle tool calls
111
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
112
+ const { name, arguments: args } = request.params;
113
+
114
+ switch (name) {
115
+ case 'list_components': {
116
+ const category = (args as { category?: string })?.category || 'all';
117
+ const filtered = listComponents(category);
118
+
119
+ const summary = filtered.map(c => ({
120
+ name: c.name,
121
+ id: c.id,
122
+ category: c.category,
123
+ description: c.description,
124
+ formats: {
125
+ react: true,
126
+ vanilla: !!c.vanilla,
127
+ },
128
+ }));
129
+
130
+ return {
131
+ content: [
132
+ {
133
+ type: 'text',
134
+ text: JSON.stringify({
135
+ total: filtered.length,
136
+ categories: getCategories(),
137
+ components: summary,
138
+ note: 'Components with vanilla: true support plain HTML/CSS/JS (no React/npm required). Use format: "vanilla" in get_component or add_component.',
139
+ }, null, 2),
140
+ },
141
+ ],
142
+ };
143
+ }
144
+
145
+ case 'get_component': {
146
+ const componentName = (args as { name: string; format?: string }).name;
147
+ const format = (args as { format?: string }).format || 'react';
148
+ const component = getComponent(componentName);
149
+
150
+ if (!component) {
151
+ return {
152
+ content: [
153
+ {
154
+ type: 'text',
155
+ text: `Component "${componentName}" not found. Use list_components to see available components.`,
156
+ },
157
+ ],
158
+ isError: true,
159
+ };
160
+ }
161
+
162
+ // Return vanilla format if requested
163
+ if (format === 'vanilla') {
164
+ if (!component.vanilla) {
165
+ return {
166
+ content: [
167
+ {
168
+ type: 'text',
169
+ text: `Vanilla HTML/CSS version not available for "${componentName}". Use format: "react" for the React version.`,
170
+ },
171
+ ],
172
+ isError: true,
173
+ };
174
+ }
175
+
176
+ return {
177
+ content: [
178
+ {
179
+ type: 'text',
180
+ text: JSON.stringify({
181
+ name: component.name,
182
+ id: component.id,
183
+ description: component.description,
184
+ category: component.category,
185
+ format: 'vanilla',
186
+ html: component.vanilla.html,
187
+ css: component.vanilla.css,
188
+ js: component.vanilla.js || null,
189
+ usage: component.vanilla.usage,
190
+ note: 'No npm dependencies required. Just add the HTML, CSS, and optional JS to your project.',
191
+ }, null, 2),
192
+ },
193
+ ],
194
+ };
195
+ }
196
+
197
+ // Default: React format
198
+ return {
199
+ content: [
200
+ {
201
+ type: 'text',
202
+ text: JSON.stringify({
203
+ name: component.name,
204
+ id: component.id,
205
+ description: component.description,
206
+ category: component.category,
207
+ format: 'react',
208
+ dependencies: component.dependencies,
209
+ props: component.props,
210
+ usage: component.usage,
211
+ source: component.source,
212
+ vanillaAvailable: !!component.vanilla,
213
+ }, null, 2),
214
+ },
215
+ ],
216
+ };
217
+ }
218
+
219
+ case 'add_component': {
220
+ const componentName = (args as { name: string; directory?: string; format?: string }).name;
221
+ const directory = (args as { directory?: string }).directory || './components';
222
+ const format = (args as { format?: string }).format || 'react';
223
+ const component = getComponent(componentName);
224
+
225
+ if (!component) {
226
+ return {
227
+ content: [
228
+ {
229
+ type: 'text',
230
+ text: `Component "${componentName}" not found. Use list_components to see available components.`,
231
+ },
232
+ ],
233
+ isError: true,
234
+ };
235
+ }
236
+
237
+ // Handle vanilla format
238
+ if (format === 'vanilla') {
239
+ if (!component.vanilla) {
240
+ return {
241
+ content: [
242
+ {
243
+ type: 'text',
244
+ text: `Vanilla HTML/CSS version not available for "${componentName}". Use format: "react" instead.`,
245
+ },
246
+ ],
247
+ isError: true,
248
+ };
249
+ }
250
+
251
+ const htmlPath = path.join(directory, `${component.id}.html`);
252
+ const cssPath = path.join(directory, `${component.id}.css`);
253
+ const jsPath = component.vanilla.js ? path.join(directory, `${component.id}.js`) : null;
254
+
255
+ return {
256
+ content: [
257
+ {
258
+ type: 'text',
259
+ text: JSON.stringify({
260
+ success: true,
261
+ component: component.name,
262
+ format: 'vanilla',
263
+ files: {
264
+ html: { path: htmlPath, content: component.vanilla.html },
265
+ css: { path: cssPath, content: component.vanilla.css },
266
+ js: jsPath ? { path: jsPath, content: component.vanilla.js } : null,
267
+ },
268
+ usage: component.vanilla.usage,
269
+ instructions: `
270
+ 1. Create the HTML file at: ${htmlPath}
271
+ 2. Create the CSS file at: ${cssPath}
272
+ ${jsPath ? `3. Create the JS file at: ${jsPath}` : ''}
273
+ ${jsPath ? '4' : '3'}. Link the CSS in your HTML <head> and JS before </body>
274
+ ${jsPath ? '5' : '4'}. No npm dependencies required!
275
+
276
+ Example HTML setup:
277
+ <link rel="stylesheet" href="${component.id}.css">
278
+ ${jsPath ? `<script src="${component.id}.js"></script>` : ''}
279
+ `.trim(),
280
+ }, null, 2),
281
+ },
282
+ ],
283
+ };
284
+ }
285
+
286
+ // Default: React format
287
+ const filePath = path.join(directory, `${component.name}.tsx`);
288
+
289
+ return {
290
+ content: [
291
+ {
292
+ type: 'text',
293
+ text: JSON.stringify({
294
+ success: true,
295
+ component: component.name,
296
+ format: 'react',
297
+ filePath: filePath,
298
+ source: component.source,
299
+ dependencies: component.dependencies,
300
+ installCommand: `npm install ${component.dependencies.join(' ')}`,
301
+ usage: component.usage,
302
+ vanillaAvailable: !!component.vanilla,
303
+ instructions: `
304
+ 1. Create the file at: ${filePath}
305
+ 2. Install dependencies: npm install ${component.dependencies.join(' ')}
306
+ 3. Import and use the component as shown in the usage example.
307
+
308
+ Note: Make sure you have 'use client' directive if using Next.js App Router.
309
+ ${component.vanilla ? '\nTip: Vanilla HTML/CSS version also available. Use format: "vanilla" to get it.' : ''}
310
+ `.trim(),
311
+ }, null, 2),
312
+ },
313
+ ],
314
+ };
315
+ }
316
+
317
+ case 'get_install_command': {
318
+ const componentName = (args as { name: string }).name;
319
+ const component = getComponent(componentName);
320
+
321
+ if (!component) {
322
+ return {
323
+ content: [
324
+ {
325
+ type: 'text',
326
+ text: `Component "${componentName}" not found.`,
327
+ },
328
+ ],
329
+ isError: true,
330
+ };
331
+ }
332
+
333
+ return {
334
+ content: [
335
+ {
336
+ type: 'text',
337
+ text: `npm install ${component.dependencies.join(' ')}`,
338
+ },
339
+ ],
340
+ };
341
+ }
342
+
343
+ default:
344
+ return {
345
+ content: [
346
+ {
347
+ type: 'text',
348
+ text: `Unknown tool: ${name}`,
349
+ },
350
+ ],
351
+ isError: true,
352
+ };
353
+ }
354
+ });
355
+
356
+ // Start the server
357
+ async function main() {
358
+ const transport = new StdioServerTransport();
359
+ await server.connect(transport);
360
+ console.error('Archyra MCP Server running on stdio');
361
+ }
362
+
363
+ main().catch(console.error);
package/package.json ADDED
@@ -0,0 +1,116 @@
1
+ {
2
+ "name": "archyra",
3
+ "version": "1.0.0",
4
+ "description": "Archyra - Beautiful animated components for React/Next.js - loading states, e-commerce interactions, chat UIs with MCP server support.",
5
+ "main": "dist/index.js",
6
+ "module": "dist/index.mjs",
7
+ "types": "dist/index.d.ts",
8
+ "bin": {
9
+ "archyra": "./dist/mcp/cli.js"
10
+ },
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "import": "./dist/index.mjs",
15
+ "require": "./dist/index.js"
16
+ },
17
+ "./styles.css": "./dist/styles.css",
18
+ "./mcp": "./dist/mcp/server.js",
19
+ "./mcp/server": "./dist/mcp/server.js",
20
+ "./mcp/server.js": "./dist/mcp/server.js"
21
+ },
22
+ "files": [
23
+ "dist",
24
+ "mcp",
25
+ "README.md",
26
+ "LICENSE"
27
+ ],
28
+ "scripts": {
29
+ "dev": "next dev",
30
+ "build": "next build",
31
+ "start": "next start",
32
+ "build:lib": "node scripts/build.js",
33
+ "build:mcp": "npm run build:mcp:server && npm run build:mcp:cli",
34
+ "build:mcp:server": "npx esbuild mcp/server.ts --bundle --platform=node --format=cjs --outfile=dist/mcp/server.js --banner:js='#!/usr/bin/env node'",
35
+ "build:mcp:cli": "npx esbuild mcp/cli.ts --bundle --platform=node --format=cjs --outfile=dist/mcp/cli.js --banner:js='#!/usr/bin/env node'",
36
+ "mcp": "node dist/mcp/server.js",
37
+ "mcp:dev": "npx tsx mcp/server.ts",
38
+ "prepublishOnly": "npm run build:lib && npm run build:mcp"
39
+ },
40
+ "keywords": [
41
+ "archyra",
42
+ "react",
43
+ "nextjs",
44
+ "animation",
45
+ "ai",
46
+ "vibe-coding",
47
+ "loading",
48
+ "spinner",
49
+ "typescript",
50
+ "components",
51
+ "ecommerce",
52
+ "cart",
53
+ "product-card",
54
+ "wishlist",
55
+ "countdown-timer",
56
+ "chat",
57
+ "framer-motion",
58
+ "tailwindcss"
59
+ ],
60
+ "author": "johnbekele",
61
+ "license": "MIT",
62
+ "repository": {
63
+ "type": "git",
64
+ "url": "https://github.com/johnbekele/Archyra"
65
+ },
66
+ "dependencies": {
67
+ "@dnd-kit/core": "^6.3.1",
68
+ "@modelcontextprotocol/sdk": "^1.25.1",
69
+ "@radix-ui/react-avatar": "^1.1.11",
70
+ "@radix-ui/react-collapsible": "^1.1.12",
71
+ "@radix-ui/react-dialog": "^1.1.15",
72
+ "@radix-ui/react-dropdown-menu": "^2.1.16",
73
+ "@radix-ui/react-label": "^2.1.8",
74
+ "@radix-ui/react-scroll-area": "^1.2.10",
75
+ "@radix-ui/react-select": "^2.2.6",
76
+ "@radix-ui/react-separator": "^1.1.8",
77
+ "@radix-ui/react-slot": "^1.2.4",
78
+ "@radix-ui/react-switch": "^1.2.6",
79
+ "@radix-ui/react-tabs": "^1.1.13",
80
+ "@radix-ui/react-toggle": "^1.1.10",
81
+ "@radix-ui/react-toggle-group": "^1.1.11",
82
+ "@radix-ui/react-tooltip": "^1.2.8",
83
+ "class-variance-authority": "^0.7.1",
84
+ "clsx": "^2.1.1",
85
+ "framer-motion": "^11.0.0",
86
+ "jszip": "^3.10.1",
87
+ "lucide-react": "^0.344.0",
88
+ "next-auth": "^4.24.13",
89
+ "next-themes": "^0.4.6",
90
+ "reactflow": "^11.11.4",
91
+ "tailwind-merge": "^3.4.0",
92
+ "tailwindcss-animate": "^1.0.7",
93
+ "tsx": "^4.21.0",
94
+ "zustand": "^5.0.9"
95
+ },
96
+ "peerDependencies": {
97
+ "react": ">=17.0.0",
98
+ "react-dom": ">=17.0.0"
99
+ },
100
+ "devDependencies": {
101
+ "@types/node": "^20.11.0",
102
+ "@types/react": "^18.2.48",
103
+ "@types/react-dom": "^18.2.18",
104
+ "autoprefixer": "^10.4.17",
105
+ "esbuild": "^0.27.2",
106
+ "eslint": "^8.56.0",
107
+ "eslint-config-next": "^14.2.0",
108
+ "next": "^14.2.0",
109
+ "postcss": "^8.4.33",
110
+ "react": "^18.3.1",
111
+ "react-dom": "^18.3.1",
112
+ "shadcn": "^3.6.2",
113
+ "tailwindcss": "^3.4.1",
114
+ "typescript": "^5.3.3"
115
+ }
116
+ }