myoperator-mcp 0.0.4 → 0.1.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/README.md +74 -0
- package/dist/index.js +584 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -96,13 +96,26 @@ Or use Command Palette → "MCP: Add Server"
|
|
|
96
96
|
|
|
97
97
|
## Available Tools
|
|
98
98
|
|
|
99
|
+
### Component Discovery
|
|
99
100
|
| Tool | Description |
|
|
100
101
|
|------|-------------|
|
|
101
102
|
| `list-components` | List all available components with descriptions |
|
|
102
103
|
| `get-component-metadata` | Get props, variants, dependencies for a component |
|
|
103
104
|
| `get-component-examples` | Get React code examples |
|
|
105
|
+
| `get-component-source` | Get full source code (copy/paste ready) |
|
|
106
|
+
|
|
107
|
+
### Installation (like shadcn)
|
|
108
|
+
| Tool | Description |
|
|
109
|
+
|------|-------------|
|
|
110
|
+
| `init-project` | Initialize project for myOperator UI (runs CLI) |
|
|
111
|
+
| `install-component` | Install a component via CLI |
|
|
112
|
+
|
|
113
|
+
### Design System
|
|
114
|
+
| Tool | Description |
|
|
115
|
+
|------|-------------|
|
|
104
116
|
| `list-design-tokens` | List design tokens (colors, spacing, radius, typography) |
|
|
105
117
|
| `get-component-accessibility` | Get accessibility guidelines and ARIA attributes |
|
|
118
|
+
| `get-installation-info` | Get npm package info and setup instructions |
|
|
106
119
|
|
|
107
120
|
---
|
|
108
121
|
|
|
@@ -148,6 +161,22 @@ Once installed, ask your AI assistant:
|
|
|
148
161
|
|
|
149
162
|
> "What keyboard shortcuts does the Table support?"
|
|
150
163
|
|
|
164
|
+
### Source Code (NEW)
|
|
165
|
+
|
|
166
|
+
> "Give me the full Button component source code"
|
|
167
|
+
|
|
168
|
+
> "Get the utils.ts file I need"
|
|
169
|
+
|
|
170
|
+
> "Get the CSS styles for the design system"
|
|
171
|
+
|
|
172
|
+
### Installation (like shadcn)
|
|
173
|
+
|
|
174
|
+
> "Initialize my project for myOperator UI"
|
|
175
|
+
|
|
176
|
+
> "Install the Button component"
|
|
177
|
+
|
|
178
|
+
> "Add badge and table components to my project"
|
|
179
|
+
|
|
151
180
|
---
|
|
152
181
|
|
|
153
182
|
## Components
|
|
@@ -226,6 +255,51 @@ Output: {
|
|
|
226
255
|
}
|
|
227
256
|
```
|
|
228
257
|
|
|
258
|
+
### `get-component-source`
|
|
259
|
+
|
|
260
|
+
Get full source code for a component (copy/paste ready).
|
|
261
|
+
|
|
262
|
+
```
|
|
263
|
+
Input: { componentName: "button" } // or "utils" or "css"
|
|
264
|
+
Output: {
|
|
265
|
+
component, file path, dependencies,
|
|
266
|
+
installCommand,
|
|
267
|
+
sourceCode (full implementation)
|
|
268
|
+
}
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
### `get-installation-info`
|
|
272
|
+
|
|
273
|
+
Get npm package info and setup instructions.
|
|
274
|
+
|
|
275
|
+
```
|
|
276
|
+
Input: (none)
|
|
277
|
+
Output: {
|
|
278
|
+
packageName, npmUrl,
|
|
279
|
+
quickStart commands,
|
|
280
|
+
manualInstallation steps,
|
|
281
|
+
dependencies
|
|
282
|
+
}
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
### `init-project`
|
|
286
|
+
|
|
287
|
+
Initialize a project for myOperator UI (runs CLI command).
|
|
288
|
+
|
|
289
|
+
```
|
|
290
|
+
Input: { cwd?: string }
|
|
291
|
+
Output: { success, command, output }
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
### `install-component`
|
|
295
|
+
|
|
296
|
+
Install a component via CLI (like shadcn).
|
|
297
|
+
|
|
298
|
+
```
|
|
299
|
+
Input: { component: "button", cwd?: string }
|
|
300
|
+
Output: { success, component, command, output }
|
|
301
|
+
```
|
|
302
|
+
|
|
229
303
|
---
|
|
230
304
|
|
|
231
305
|
## Development
|
package/dist/index.js
CHANGED
|
@@ -7,6 +7,266 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
|
|
7
7
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
8
8
|
|
|
9
9
|
// src/data/metadata.ts
|
|
10
|
+
var componentSourceCode = {
|
|
11
|
+
button: `import * as React from "react"
|
|
12
|
+
import { Slot } from "@radix-ui/react-slot"
|
|
13
|
+
import { cva, type VariantProps } from "class-variance-authority"
|
|
14
|
+
import { Loader2 } from "lucide-react"
|
|
15
|
+
|
|
16
|
+
import { cn } from "@/lib/utils"
|
|
17
|
+
|
|
18
|
+
const buttonVariants = cva(
|
|
19
|
+
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
|
|
20
|
+
{
|
|
21
|
+
variants: {
|
|
22
|
+
variant: {
|
|
23
|
+
default: "bg-[#343E55] text-white hover:bg-[#343E55]/90",
|
|
24
|
+
destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
|
|
25
|
+
outline: "border border-[#343E55] bg-transparent text-[#343E55] hover:bg-[#343E55] hover:text-white",
|
|
26
|
+
secondary: "bg-[#343E55]/20 text-[#343E55] hover:bg-[#343E55]/30",
|
|
27
|
+
ghost: "hover:bg-[#343E55]/10 hover:text-[#343E55]",
|
|
28
|
+
link: "text-[#343E55] underline-offset-4 hover:underline",
|
|
29
|
+
},
|
|
30
|
+
size: {
|
|
31
|
+
default: "py-2.5 px-4",
|
|
32
|
+
sm: "py-2 px-3 text-xs",
|
|
33
|
+
lg: "py-3 px-6",
|
|
34
|
+
icon: "p-2.5",
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
defaultVariants: {
|
|
38
|
+
variant: "default",
|
|
39
|
+
size: "default",
|
|
40
|
+
},
|
|
41
|
+
}
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
export interface ButtonProps
|
|
45
|
+
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
|
|
46
|
+
VariantProps<typeof buttonVariants> {
|
|
47
|
+
asChild?: boolean
|
|
48
|
+
leftIcon?: React.ReactNode
|
|
49
|
+
rightIcon?: React.ReactNode
|
|
50
|
+
loading?: boolean
|
|
51
|
+
loadingText?: string
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
|
55
|
+
({ className, variant, size, asChild = false, leftIcon, rightIcon, loading = false, loadingText, children, disabled, ...props }, ref) => {
|
|
56
|
+
const Comp = asChild ? Slot : "button"
|
|
57
|
+
return (
|
|
58
|
+
<Comp
|
|
59
|
+
className={cn(buttonVariants({ variant, size, className }))}
|
|
60
|
+
ref={ref}
|
|
61
|
+
disabled={disabled || loading}
|
|
62
|
+
{...props}
|
|
63
|
+
>
|
|
64
|
+
{loading ? (
|
|
65
|
+
<>
|
|
66
|
+
<Loader2 className="animate-spin" />
|
|
67
|
+
{loadingText || children}
|
|
68
|
+
</>
|
|
69
|
+
) : (
|
|
70
|
+
<>
|
|
71
|
+
{leftIcon}
|
|
72
|
+
{children}
|
|
73
|
+
{rightIcon}
|
|
74
|
+
</>
|
|
75
|
+
)}
|
|
76
|
+
</Comp>
|
|
77
|
+
)
|
|
78
|
+
}
|
|
79
|
+
)
|
|
80
|
+
Button.displayName = "Button"
|
|
81
|
+
|
|
82
|
+
export { Button, buttonVariants }`,
|
|
83
|
+
badge: `import * as React from "react"
|
|
84
|
+
import { cva, type VariantProps } from "class-variance-authority"
|
|
85
|
+
|
|
86
|
+
import { cn } from "@/lib/utils"
|
|
87
|
+
|
|
88
|
+
const badgeVariants = cva(
|
|
89
|
+
"inline-flex items-center justify-center rounded-full text-sm font-semibold transition-colors whitespace-nowrap",
|
|
90
|
+
{
|
|
91
|
+
variants: {
|
|
92
|
+
variant: {
|
|
93
|
+
active: "bg-[#E5FFF5] text-[#00A651]",
|
|
94
|
+
failed: "bg-[#FFECEC] text-[#FF3B3B]",
|
|
95
|
+
disabled: "bg-[#F3F5F6] text-[#6B7280]",
|
|
96
|
+
default: "bg-[#F3F5F6] text-[#333333]",
|
|
97
|
+
},
|
|
98
|
+
size: {
|
|
99
|
+
default: "px-3 py-1",
|
|
100
|
+
sm: "px-2 py-0.5 text-xs",
|
|
101
|
+
lg: "px-4 py-1.5",
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
defaultVariants: {
|
|
105
|
+
variant: "default",
|
|
106
|
+
size: "default",
|
|
107
|
+
},
|
|
108
|
+
}
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
export interface BadgeProps
|
|
112
|
+
extends React.HTMLAttributes<HTMLDivElement>,
|
|
113
|
+
VariantProps<typeof badgeVariants> {
|
|
114
|
+
leftIcon?: React.ReactNode
|
|
115
|
+
rightIcon?: React.ReactNode
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const Badge = React.forwardRef<HTMLDivElement, BadgeProps>(
|
|
119
|
+
({ className, variant, size, leftIcon, rightIcon, children, ...props }, ref) => {
|
|
120
|
+
return (
|
|
121
|
+
<div
|
|
122
|
+
className={cn(badgeVariants({ variant, size, className }), "gap-1")}
|
|
123
|
+
ref={ref}
|
|
124
|
+
{...props}
|
|
125
|
+
>
|
|
126
|
+
{leftIcon && <span className="[&_svg]:size-3">{leftIcon}</span>}
|
|
127
|
+
{children}
|
|
128
|
+
{rightIcon && <span className="[&_svg]:size-3">{rightIcon}</span>}
|
|
129
|
+
</div>
|
|
130
|
+
)
|
|
131
|
+
}
|
|
132
|
+
)
|
|
133
|
+
Badge.displayName = "Badge"
|
|
134
|
+
|
|
135
|
+
export { Badge, badgeVariants }`,
|
|
136
|
+
tag: `import * as React from "react"
|
|
137
|
+
import { cva, type VariantProps } from "class-variance-authority"
|
|
138
|
+
|
|
139
|
+
import { cn } from "@/lib/utils"
|
|
140
|
+
|
|
141
|
+
const tagVariants = cva(
|
|
142
|
+
"inline-flex items-center justify-center rounded text-sm transition-colors",
|
|
143
|
+
{
|
|
144
|
+
variants: {
|
|
145
|
+
variant: {
|
|
146
|
+
default: "bg-[#F3F4F6] text-[#333333]",
|
|
147
|
+
primary: "bg-[#343E55]/10 text-[#343E55]",
|
|
148
|
+
secondary: "bg-[#E5E7EB] text-[#374151]",
|
|
149
|
+
success: "bg-[#E5FFF5] text-[#00A651]",
|
|
150
|
+
warning: "bg-[#FFF8E5] text-[#F59E0B]",
|
|
151
|
+
error: "bg-[#FFECEC] text-[#FF3B3B]",
|
|
152
|
+
},
|
|
153
|
+
size: {
|
|
154
|
+
default: "px-2 py-1",
|
|
155
|
+
sm: "px-1.5 py-0.5 text-xs",
|
|
156
|
+
lg: "px-3 py-1.5",
|
|
157
|
+
},
|
|
158
|
+
interactive: {
|
|
159
|
+
true: "cursor-pointer hover:bg-[#E5E7EB] active:bg-[#D1D5DB]",
|
|
160
|
+
false: "",
|
|
161
|
+
},
|
|
162
|
+
selected: {
|
|
163
|
+
true: "ring-2 ring-[#343E55] ring-offset-1",
|
|
164
|
+
false: "",
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
defaultVariants: {
|
|
168
|
+
variant: "default",
|
|
169
|
+
size: "default",
|
|
170
|
+
interactive: false,
|
|
171
|
+
selected: false,
|
|
172
|
+
},
|
|
173
|
+
}
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
export interface TagProps
|
|
177
|
+
extends React.HTMLAttributes<HTMLSpanElement>,
|
|
178
|
+
VariantProps<typeof tagVariants> {
|
|
179
|
+
label?: string
|
|
180
|
+
interactive?: boolean
|
|
181
|
+
selected?: boolean
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const Tag = React.forwardRef<HTMLSpanElement, TagProps>(
|
|
185
|
+
({ className, variant, size, interactive, selected, label, children, ...props }, ref) => {
|
|
186
|
+
return (
|
|
187
|
+
<span
|
|
188
|
+
className={cn(tagVariants({ variant, size, interactive, selected, className }))}
|
|
189
|
+
ref={ref}
|
|
190
|
+
role={interactive ? "button" : undefined}
|
|
191
|
+
tabIndex={interactive ? 0 : undefined}
|
|
192
|
+
aria-selected={selected}
|
|
193
|
+
{...props}
|
|
194
|
+
>
|
|
195
|
+
{label && <span className="font-semibold mr-1">{label}</span>}
|
|
196
|
+
<span className="font-normal">{children}</span>
|
|
197
|
+
</span>
|
|
198
|
+
)
|
|
199
|
+
}
|
|
200
|
+
)
|
|
201
|
+
Tag.displayName = "Tag"
|
|
202
|
+
|
|
203
|
+
export { Tag, tagVariants }`
|
|
204
|
+
};
|
|
205
|
+
var utilsSourceCode = `import { type ClassValue, clsx } from "clsx"
|
|
206
|
+
import { twMerge } from "tailwind-merge"
|
|
207
|
+
|
|
208
|
+
export function cn(...inputs: ClassValue[]) {
|
|
209
|
+
return twMerge(clsx(inputs))
|
|
210
|
+
}`;
|
|
211
|
+
var cssStyles = `@tailwind base;
|
|
212
|
+
@tailwind components;
|
|
213
|
+
@tailwind utilities;
|
|
214
|
+
|
|
215
|
+
@layer base {
|
|
216
|
+
:root {
|
|
217
|
+
--background: 0 0% 100%;
|
|
218
|
+
--foreground: 222.2 84% 4.9%;
|
|
219
|
+
--card: 0 0% 100%;
|
|
220
|
+
--card-foreground: 222.2 84% 4.9%;
|
|
221
|
+
--popover: 0 0% 100%;
|
|
222
|
+
--popover-foreground: 222.2 84% 4.9%;
|
|
223
|
+
--primary: 222.2 47.4% 11.2%;
|
|
224
|
+
--primary-foreground: 210 40% 98%;
|
|
225
|
+
--secondary: 210 40% 96.1%;
|
|
226
|
+
--secondary-foreground: 222.2 47.4% 11.2%;
|
|
227
|
+
--muted: 210 40% 96.1%;
|
|
228
|
+
--muted-foreground: 215.4 16.3% 46.9%;
|
|
229
|
+
--accent: 210 40% 96.1%;
|
|
230
|
+
--accent-foreground: 222.2 47.4% 11.2%;
|
|
231
|
+
--destructive: 0 84.2% 60.2%;
|
|
232
|
+
--destructive-foreground: 210 40% 98%;
|
|
233
|
+
--border: 214.3 31.8% 91.4%;
|
|
234
|
+
--input: 214.3 31.8% 91.4%;
|
|
235
|
+
--ring: 222.2 84% 4.9%;
|
|
236
|
+
--radius: 0.5rem;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
.dark {
|
|
240
|
+
--background: 222.2 84% 4.9%;
|
|
241
|
+
--foreground: 210 40% 98%;
|
|
242
|
+
--card: 222.2 84% 4.9%;
|
|
243
|
+
--card-foreground: 210 40% 98%;
|
|
244
|
+
--popover: 222.2 84% 4.9%;
|
|
245
|
+
--popover-foreground: 210 40% 98%;
|
|
246
|
+
--primary: 210 40% 98%;
|
|
247
|
+
--primary-foreground: 222.2 47.4% 11.2%;
|
|
248
|
+
--secondary: 217.2 32.6% 17.5%;
|
|
249
|
+
--secondary-foreground: 210 40% 98%;
|
|
250
|
+
--muted: 217.2 32.6% 17.5%;
|
|
251
|
+
--muted-foreground: 215 20.2% 65.1%;
|
|
252
|
+
--accent: 217.2 32.6% 17.5%;
|
|
253
|
+
--accent-foreground: 210 40% 98%;
|
|
254
|
+
--destructive: 0 62.8% 30.6%;
|
|
255
|
+
--destructive-foreground: 210 40% 98%;
|
|
256
|
+
--border: 217.2 32.6% 17.5%;
|
|
257
|
+
--input: 217.2 32.6% 17.5%;
|
|
258
|
+
--ring: 212.7 26.8% 83.9%;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
@layer base {
|
|
263
|
+
* {
|
|
264
|
+
@apply border-border;
|
|
265
|
+
}
|
|
266
|
+
body {
|
|
267
|
+
@apply bg-background text-foreground;
|
|
268
|
+
}
|
|
269
|
+
}`;
|
|
10
270
|
var componentMetadata = {
|
|
11
271
|
button: {
|
|
12
272
|
name: "Button",
|
|
@@ -1276,17 +1536,340 @@ function registerGetComponentAccessibility(server) {
|
|
|
1276
1536
|
);
|
|
1277
1537
|
}
|
|
1278
1538
|
|
|
1539
|
+
// src/server/tools/get-component-source.ts
|
|
1540
|
+
import { z as z5 } from "zod";
|
|
1541
|
+
function registerGetComponentSource(server) {
|
|
1542
|
+
server.tool(
|
|
1543
|
+
"get-component-source",
|
|
1544
|
+
"Get the full source code for a myOperator UI component (copy/paste ready)",
|
|
1545
|
+
{
|
|
1546
|
+
componentName: z5.string().describe(
|
|
1547
|
+
"The name of the component (e.g., 'button', 'badge', 'tag') or 'utils' for the cn() helper or 'css' for styles"
|
|
1548
|
+
)
|
|
1549
|
+
},
|
|
1550
|
+
async ({ componentName }) => {
|
|
1551
|
+
const name = componentName.toLowerCase();
|
|
1552
|
+
if (name === "utils" || name === "cn") {
|
|
1553
|
+
return {
|
|
1554
|
+
content: [
|
|
1555
|
+
{
|
|
1556
|
+
type: "text",
|
|
1557
|
+
text: JSON.stringify(
|
|
1558
|
+
{
|
|
1559
|
+
file: "lib/utils.ts",
|
|
1560
|
+
description: "Utility function for merging Tailwind classes",
|
|
1561
|
+
dependencies: ["clsx", "tailwind-merge"],
|
|
1562
|
+
installCommand: "npm install clsx tailwind-merge",
|
|
1563
|
+
sourceCode: utilsSourceCode
|
|
1564
|
+
},
|
|
1565
|
+
null,
|
|
1566
|
+
2
|
|
1567
|
+
)
|
|
1568
|
+
}
|
|
1569
|
+
]
|
|
1570
|
+
};
|
|
1571
|
+
}
|
|
1572
|
+
if (name === "css" || name === "styles") {
|
|
1573
|
+
return {
|
|
1574
|
+
content: [
|
|
1575
|
+
{
|
|
1576
|
+
type: "text",
|
|
1577
|
+
text: JSON.stringify(
|
|
1578
|
+
{
|
|
1579
|
+
file: "index.css",
|
|
1580
|
+
description: "CSS styles with Tailwind and design tokens",
|
|
1581
|
+
dependencies: ["tailwindcss"],
|
|
1582
|
+
sourceCode: cssStyles
|
|
1583
|
+
},
|
|
1584
|
+
null,
|
|
1585
|
+
2
|
|
1586
|
+
)
|
|
1587
|
+
}
|
|
1588
|
+
]
|
|
1589
|
+
};
|
|
1590
|
+
}
|
|
1591
|
+
const sourceCode = componentSourceCode[name];
|
|
1592
|
+
if (!sourceCode) {
|
|
1593
|
+
const availableComponents = [
|
|
1594
|
+
...Object.keys(componentSourceCode),
|
|
1595
|
+
"utils",
|
|
1596
|
+
"css"
|
|
1597
|
+
].join(", ");
|
|
1598
|
+
return {
|
|
1599
|
+
content: [
|
|
1600
|
+
{
|
|
1601
|
+
type: "text",
|
|
1602
|
+
text: `Error: Source code for "${componentName}" not found. Available: ${availableComponents}`
|
|
1603
|
+
}
|
|
1604
|
+
],
|
|
1605
|
+
isError: true
|
|
1606
|
+
};
|
|
1607
|
+
}
|
|
1608
|
+
const dependenciesMap = {
|
|
1609
|
+
button: [
|
|
1610
|
+
"@radix-ui/react-slot",
|
|
1611
|
+
"class-variance-authority",
|
|
1612
|
+
"clsx",
|
|
1613
|
+
"tailwind-merge",
|
|
1614
|
+
"lucide-react"
|
|
1615
|
+
],
|
|
1616
|
+
badge: ["class-variance-authority", "clsx", "tailwind-merge"],
|
|
1617
|
+
tag: ["class-variance-authority", "clsx", "tailwind-merge"]
|
|
1618
|
+
};
|
|
1619
|
+
const dependencies = dependenciesMap[name] || [];
|
|
1620
|
+
return {
|
|
1621
|
+
content: [
|
|
1622
|
+
{
|
|
1623
|
+
type: "text",
|
|
1624
|
+
text: JSON.stringify(
|
|
1625
|
+
{
|
|
1626
|
+
component: name,
|
|
1627
|
+
file: `components/ui/${name}.tsx`,
|
|
1628
|
+
dependencies,
|
|
1629
|
+
installCommand: dependencies.length > 0 ? `npm install ${dependencies.join(" ")}` : null,
|
|
1630
|
+
requiredFiles: [
|
|
1631
|
+
{
|
|
1632
|
+
path: "lib/utils.ts",
|
|
1633
|
+
note: "Required for cn() function - use get-component-source with 'utils' to get this file"
|
|
1634
|
+
}
|
|
1635
|
+
],
|
|
1636
|
+
sourceCode
|
|
1637
|
+
},
|
|
1638
|
+
null,
|
|
1639
|
+
2
|
|
1640
|
+
)
|
|
1641
|
+
}
|
|
1642
|
+
]
|
|
1643
|
+
};
|
|
1644
|
+
}
|
|
1645
|
+
);
|
|
1646
|
+
}
|
|
1647
|
+
|
|
1648
|
+
// src/server/tools/get-installation-info.ts
|
|
1649
|
+
function registerGetInstallationInfo(server) {
|
|
1650
|
+
server.tool(
|
|
1651
|
+
"get-installation-info",
|
|
1652
|
+
"Get installation instructions and npm package info for myOperator UI",
|
|
1653
|
+
{},
|
|
1654
|
+
async () => {
|
|
1655
|
+
const installationInfo = {
|
|
1656
|
+
packageName: "myoperator-ui",
|
|
1657
|
+
npmUrl: "https://www.npmjs.com/package/myoperator-ui",
|
|
1658
|
+
description: "CLI for adding myOperator UI components to your project",
|
|
1659
|
+
quickStart: {
|
|
1660
|
+
step1: "npx myoperator-ui init",
|
|
1661
|
+
step2: "npx myoperator-ui add button",
|
|
1662
|
+
description: "Initialize project and add components via CLI"
|
|
1663
|
+
},
|
|
1664
|
+
manualInstallation: {
|
|
1665
|
+
description: "If you prefer to manually add components:",
|
|
1666
|
+
steps: [
|
|
1667
|
+
{
|
|
1668
|
+
step: 1,
|
|
1669
|
+
title: "Install dependencies",
|
|
1670
|
+
command: "npm install class-variance-authority clsx tailwind-merge"
|
|
1671
|
+
},
|
|
1672
|
+
{
|
|
1673
|
+
step: 2,
|
|
1674
|
+
title: "Create utils file",
|
|
1675
|
+
path: "lib/utils.ts",
|
|
1676
|
+
note: "Use get-component-source with 'utils' to get the code"
|
|
1677
|
+
},
|
|
1678
|
+
{
|
|
1679
|
+
step: 3,
|
|
1680
|
+
title: "Add CSS styles",
|
|
1681
|
+
path: "index.css or globals.css",
|
|
1682
|
+
note: "Use get-component-source with 'css' to get the styles"
|
|
1683
|
+
},
|
|
1684
|
+
{
|
|
1685
|
+
step: 4,
|
|
1686
|
+
title: "Copy component",
|
|
1687
|
+
path: "components/ui/[component].tsx",
|
|
1688
|
+
note: "Use get-component-source with component name to get the code"
|
|
1689
|
+
}
|
|
1690
|
+
]
|
|
1691
|
+
},
|
|
1692
|
+
peerDependencies: {
|
|
1693
|
+
react: "^18.0.0",
|
|
1694
|
+
"react-dom": "^18.0.0",
|
|
1695
|
+
tailwindcss: "^3.4.0"
|
|
1696
|
+
},
|
|
1697
|
+
optionalDependencies: {
|
|
1698
|
+
"@radix-ui/react-slot": "For Button asChild prop",
|
|
1699
|
+
"@radix-ui/react-dropdown-menu": "For DropdownMenu component",
|
|
1700
|
+
"lucide-react": "For icons"
|
|
1701
|
+
},
|
|
1702
|
+
tailwindConfig: {
|
|
1703
|
+
note: "Add these to your tailwind.config.js",
|
|
1704
|
+
content: ["./components/**/*.{ts,tsx}"],
|
|
1705
|
+
plugins: ["tailwindcss-animate"]
|
|
1706
|
+
},
|
|
1707
|
+
repository: "https://github.com/Ankish8/storybook-npm",
|
|
1708
|
+
documentation: "https://storybook-npm.vercel.app"
|
|
1709
|
+
};
|
|
1710
|
+
return {
|
|
1711
|
+
content: [
|
|
1712
|
+
{
|
|
1713
|
+
type: "text",
|
|
1714
|
+
text: JSON.stringify(installationInfo, null, 2)
|
|
1715
|
+
}
|
|
1716
|
+
]
|
|
1717
|
+
};
|
|
1718
|
+
}
|
|
1719
|
+
);
|
|
1720
|
+
}
|
|
1721
|
+
|
|
1722
|
+
// src/server/tools/install-component.ts
|
|
1723
|
+
import { z as z6 } from "zod";
|
|
1724
|
+
import { exec } from "child_process";
|
|
1725
|
+
import { promisify } from "util";
|
|
1726
|
+
var execAsync = promisify(exec);
|
|
1727
|
+
function registerInstallComponent(server) {
|
|
1728
|
+
server.tool(
|
|
1729
|
+
"install-component",
|
|
1730
|
+
"Install a myOperator UI component using the CLI (runs: npx myoperator-ui add <component>)",
|
|
1731
|
+
{
|
|
1732
|
+
component: z6.string().describe("The name of the component to install (e.g., 'button', 'badge', 'table')"),
|
|
1733
|
+
cwd: z6.string().optional().describe("Working directory to run the command in (defaults to current directory)")
|
|
1734
|
+
},
|
|
1735
|
+
async ({ component, cwd }) => {
|
|
1736
|
+
const componentName = component.toLowerCase();
|
|
1737
|
+
const availableComponents = getComponentNames();
|
|
1738
|
+
if (!availableComponents.includes(componentName)) {
|
|
1739
|
+
return {
|
|
1740
|
+
content: [
|
|
1741
|
+
{
|
|
1742
|
+
type: "text",
|
|
1743
|
+
text: `Error: Component "${component}" not found. Available components: ${availableComponents.join(", ")}`
|
|
1744
|
+
}
|
|
1745
|
+
],
|
|
1746
|
+
isError: true
|
|
1747
|
+
};
|
|
1748
|
+
}
|
|
1749
|
+
try {
|
|
1750
|
+
const command = `npx myoperator-ui add ${componentName}`;
|
|
1751
|
+
const options = cwd ? { cwd } : {};
|
|
1752
|
+
const { stdout, stderr } = await execAsync(command, options);
|
|
1753
|
+
return {
|
|
1754
|
+
content: [
|
|
1755
|
+
{
|
|
1756
|
+
type: "text",
|
|
1757
|
+
text: JSON.stringify(
|
|
1758
|
+
{
|
|
1759
|
+
success: true,
|
|
1760
|
+
component: componentName,
|
|
1761
|
+
command,
|
|
1762
|
+
output: stdout || "Component installed successfully",
|
|
1763
|
+
warnings: stderr || null
|
|
1764
|
+
},
|
|
1765
|
+
null,
|
|
1766
|
+
2
|
|
1767
|
+
)
|
|
1768
|
+
}
|
|
1769
|
+
]
|
|
1770
|
+
};
|
|
1771
|
+
} catch (error) {
|
|
1772
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1773
|
+
return {
|
|
1774
|
+
content: [
|
|
1775
|
+
{
|
|
1776
|
+
type: "text",
|
|
1777
|
+
text: JSON.stringify(
|
|
1778
|
+
{
|
|
1779
|
+
success: false,
|
|
1780
|
+
component: componentName,
|
|
1781
|
+
error: errorMessage,
|
|
1782
|
+
suggestion: "Make sure you have initialized the project first with: npx myoperator-ui init"
|
|
1783
|
+
},
|
|
1784
|
+
null,
|
|
1785
|
+
2
|
|
1786
|
+
)
|
|
1787
|
+
}
|
|
1788
|
+
],
|
|
1789
|
+
isError: true
|
|
1790
|
+
};
|
|
1791
|
+
}
|
|
1792
|
+
}
|
|
1793
|
+
);
|
|
1794
|
+
}
|
|
1795
|
+
|
|
1796
|
+
// src/server/tools/init-project.ts
|
|
1797
|
+
import { z as z7 } from "zod";
|
|
1798
|
+
import { exec as exec2 } from "child_process";
|
|
1799
|
+
import { promisify as promisify2 } from "util";
|
|
1800
|
+
var execAsync2 = promisify2(exec2);
|
|
1801
|
+
function registerInitProject(server) {
|
|
1802
|
+
server.tool(
|
|
1803
|
+
"init-project",
|
|
1804
|
+
"Initialize a project for myOperator UI components (runs: npx myoperator-ui init)",
|
|
1805
|
+
{
|
|
1806
|
+
cwd: z7.string().optional().describe("Working directory to run the command in (defaults to current directory)")
|
|
1807
|
+
},
|
|
1808
|
+
async ({ cwd }) => {
|
|
1809
|
+
try {
|
|
1810
|
+
const command = "npx myoperator-ui init";
|
|
1811
|
+
const options = cwd ? { cwd } : {};
|
|
1812
|
+
const { stdout, stderr } = await execAsync2(command, options);
|
|
1813
|
+
return {
|
|
1814
|
+
content: [
|
|
1815
|
+
{
|
|
1816
|
+
type: "text",
|
|
1817
|
+
text: JSON.stringify(
|
|
1818
|
+
{
|
|
1819
|
+
success: true,
|
|
1820
|
+
command,
|
|
1821
|
+
output: stdout || "Project initialized successfully",
|
|
1822
|
+
warnings: stderr || null,
|
|
1823
|
+
nextSteps: [
|
|
1824
|
+
"Run 'install-component' to add components",
|
|
1825
|
+
"Or use: npx myoperator-ui add button"
|
|
1826
|
+
]
|
|
1827
|
+
},
|
|
1828
|
+
null,
|
|
1829
|
+
2
|
|
1830
|
+
)
|
|
1831
|
+
}
|
|
1832
|
+
]
|
|
1833
|
+
};
|
|
1834
|
+
} catch (error) {
|
|
1835
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1836
|
+
return {
|
|
1837
|
+
content: [
|
|
1838
|
+
{
|
|
1839
|
+
type: "text",
|
|
1840
|
+
text: JSON.stringify(
|
|
1841
|
+
{
|
|
1842
|
+
success: false,
|
|
1843
|
+
error: errorMessage,
|
|
1844
|
+
suggestion: "Make sure you're in a project directory with package.json and tailwind configured"
|
|
1845
|
+
},
|
|
1846
|
+
null,
|
|
1847
|
+
2
|
|
1848
|
+
)
|
|
1849
|
+
}
|
|
1850
|
+
],
|
|
1851
|
+
isError: true
|
|
1852
|
+
};
|
|
1853
|
+
}
|
|
1854
|
+
}
|
|
1855
|
+
);
|
|
1856
|
+
}
|
|
1857
|
+
|
|
1279
1858
|
// src/server/index.ts
|
|
1280
1859
|
function createServer() {
|
|
1281
1860
|
const server = new McpServer({
|
|
1282
1861
|
name: "myoperator-mcp",
|
|
1283
|
-
version: "0.0
|
|
1862
|
+
version: "0.1.0"
|
|
1284
1863
|
});
|
|
1285
1864
|
registerListComponents(server);
|
|
1286
1865
|
registerGetComponentMetadata(server);
|
|
1287
1866
|
registerGetComponentExamples(server);
|
|
1867
|
+
registerGetComponentSource(server);
|
|
1868
|
+
registerInitProject(server);
|
|
1869
|
+
registerInstallComponent(server);
|
|
1288
1870
|
registerListDesignTokens(server);
|
|
1289
1871
|
registerGetComponentAccessibility(server);
|
|
1872
|
+
registerGetInstallationInfo(server);
|
|
1290
1873
|
return server;
|
|
1291
1874
|
}
|
|
1292
1875
|
|
package/package.json
CHANGED