@eaperezc/mcpgen 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.
@@ -0,0 +1,623 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from 'commander';
3
+ import { mkdir, writeFile, access, readFile } from 'fs/promises';
4
+ import { join } from 'path';
5
+
6
+ function toPascalCase(str) {
7
+ return str.split(/[-_\s]+/).map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join("");
8
+ }
9
+ function toKebabCase(str) {
10
+ return str.replace(/([a-z])([A-Z])/g, "$1-$2").replace(/[\s_]+/g, "-").toLowerCase();
11
+ }
12
+ async function exists(path) {
13
+ try {
14
+ await access(path);
15
+ return true;
16
+ } catch {
17
+ return false;
18
+ }
19
+ }
20
+ function toolTemplate(className, toolName) {
21
+ return `import { BaseTool } from 'mcpkit';
22
+ import { z } from 'zod';
23
+
24
+ /**
25
+ * ${className} - Description of what this tool does
26
+ */
27
+ export class ${className} extends BaseTool {
28
+ name = '${toolName}';
29
+ description = 'TODO: Add description';
30
+
31
+ schema = z.object({
32
+ // TODO: Define your input schema
33
+ input: z.string().describe('Input parameter'),
34
+ });
35
+
36
+ async execute(input: z.infer<typeof this.schema>) {
37
+ // TODO: Implement your tool logic
38
+ return {
39
+ content: {
40
+ result: \`Processed: \${input.input}\`,
41
+ },
42
+ };
43
+ }
44
+ }
45
+ `;
46
+ }
47
+ function resourceTemplate(className, resourceName) {
48
+ return `import { BaseResource } from 'mcpkit';
49
+
50
+ /**
51
+ * ${className} - Description of what this resource provides
52
+ */
53
+ export class ${className} extends BaseResource {
54
+ uri = '${resourceName}://data';
55
+ name = '${className}';
56
+ description = 'TODO: Add description';
57
+
58
+ async read() {
59
+ // TODO: Implement your resource logic
60
+ return {
61
+ contents: [
62
+ this.json({
63
+ // Your data here
64
+ example: 'data',
65
+ }),
66
+ ],
67
+ };
68
+ }
69
+ }
70
+ `;
71
+ }
72
+ function promptTemplate(className, promptName) {
73
+ return `import { BasePrompt } from 'mcpkit';
74
+ import { z } from 'zod';
75
+
76
+ /**
77
+ * ${className} - Description of what this prompt does
78
+ */
79
+ export class ${className} extends BasePrompt {
80
+ name = '${promptName}';
81
+ description = 'TODO: Add description';
82
+
83
+ arguments = z.object({
84
+ // TODO: Define your arguments schema
85
+ topic: z.string().describe('The topic to discuss'),
86
+ });
87
+
88
+ async render(args: z.infer<typeof this.arguments>) {
89
+ // TODO: Implement your prompt logic
90
+ return {
91
+ messages: [
92
+ this.user(\`Please help me with: \${args.topic}\`),
93
+ ],
94
+ };
95
+ }
96
+ }
97
+ `;
98
+ }
99
+ async function updateIndexFile(indexPath, className, fileName) {
100
+ let content = "";
101
+ if (await exists(indexPath)) {
102
+ content = await readFile(indexPath, "utf-8");
103
+ }
104
+ const exportLine = `export { ${className} } from './${fileName}.js';`;
105
+ if (!content.includes(exportLine)) {
106
+ const lines = content.split("\n").filter(
107
+ (line) => line.trim() && !line.trim().startsWith("//")
108
+ );
109
+ lines.push(exportLine);
110
+ content = lines.join("\n") + "\n";
111
+ await writeFile(indexPath, content);
112
+ }
113
+ }
114
+ async function generateComponent(options) {
115
+ const { type, name } = options;
116
+ const className = toPascalCase(name) + (type === "tool" ? "Tool" : type === "resource" ? "Resource" : "Prompt");
117
+ const fileName = className;
118
+ const kebabName = toKebabCase(name);
119
+ const typeDir = type === "tool" ? "tools" : type === "resource" ? "resources" : "prompts";
120
+ const srcDir = join(process.cwd(), "src", typeDir);
121
+ const filePath = join(srcDir, `${fileName}.ts`);
122
+ const indexPath = join(srcDir, "index.ts");
123
+ if (!await exists(join(process.cwd(), "src"))) {
124
+ throw new Error('No src/ directory found. Are you in an mcpkit project? Run "mcpkit init" first.');
125
+ }
126
+ await mkdir(srcDir, { recursive: true });
127
+ if (await exists(filePath)) {
128
+ throw new Error(`${type} '${fileName}' already exists at ${filePath}`);
129
+ }
130
+ let content;
131
+ switch (type) {
132
+ case "tool":
133
+ content = toolTemplate(className, kebabName);
134
+ break;
135
+ case "resource":
136
+ content = resourceTemplate(className, kebabName);
137
+ break;
138
+ case "prompt":
139
+ content = promptTemplate(className, kebabName);
140
+ break;
141
+ default:
142
+ throw new Error(`Unknown component type: ${type}`);
143
+ }
144
+ await writeFile(filePath, content);
145
+ console.log(`
146
+ \u2705 Created ${type}: ${filePath.replace(process.cwd(), ".")}`);
147
+ await updateIndexFile(indexPath, className, fileName);
148
+ console.log(` Updated: ${indexPath.replace(process.cwd(), ".")}`);
149
+ console.log(`
150
+ Next steps:
151
+
152
+ 1. Edit src/${typeDir}/${fileName}.ts to implement your ${type}
153
+ 2. Register it in src/index.ts:
154
+
155
+ import { ${className} } from './tools/${fileName}.js';
156
+ server.${type}(new ${className}());
157
+ `);
158
+ }
159
+
160
+ // src/cli/templates/index.ts
161
+ var packageJsonTemplate = (name, description) => `{
162
+ "name": "${name}",
163
+ "version": "0.1.0",
164
+ "description": "${description}",
165
+ "type": "module",
166
+ "main": "dist/index.js",
167
+ "scripts": {
168
+ "build": "tsc",
169
+ "dev": "tsx watch src/index.ts",
170
+ "start": "node dist/index.js",
171
+ "test": "vitest run",
172
+ "test:watch": "vitest",
173
+ "lint": "eslint src",
174
+ "typecheck": "tsc --noEmit"
175
+ },
176
+ "keywords": ["mcp", "model-context-protocol"],
177
+ "license": "MIT",
178
+ "dependencies": {
179
+ "@eaperezc/mcpgen": "^0.1.0",
180
+ "@modelcontextprotocol/sdk": "^1.11.0",
181
+ "zod": "^3.23.8"
182
+ },
183
+ "devDependencies": {
184
+ "@types/node": "^22.10.0",
185
+ "typescript": "^5.7.2",
186
+ "tsx": "^4.19.2",
187
+ "vitest": "^2.1.8"
188
+ },
189
+ "engines": {
190
+ "node": ">=18.0.0"
191
+ }
192
+ }
193
+ `;
194
+ var tsconfigTemplate = () => `{
195
+ "compilerOptions": {
196
+ "target": "ES2022",
197
+ "module": "ESNext",
198
+ "moduleResolution": "bundler",
199
+ "lib": ["ES2022"],
200
+ "strict": true,
201
+ "esModuleInterop": true,
202
+ "skipLibCheck": true,
203
+ "forceConsistentCasingInFileNames": true,
204
+ "declaration": true,
205
+ "outDir": "./dist",
206
+ "rootDir": "./src",
207
+ "resolveJsonModule": true
208
+ },
209
+ "include": ["src/**/*"],
210
+ "exclude": ["node_modules", "dist"]
211
+ }
212
+ `;
213
+ var gitignoreTemplate = () => `# Dependencies
214
+ node_modules/
215
+
216
+ # Build output
217
+ dist/
218
+
219
+ # Environment files
220
+ .env
221
+ .env.local
222
+ .env.*.local
223
+
224
+ # IDE
225
+ .idea/
226
+ .vscode/
227
+ *.swp
228
+ *.swo
229
+
230
+ # OS
231
+ .DS_Store
232
+ Thumbs.db
233
+
234
+ # Logs
235
+ *.log
236
+ `;
237
+ var mainIndexTemplate = (name, transport) => {
238
+ if (transport === "http") {
239
+ return `import { McpServer } from '@eaperezc/mcpgen';
240
+ import { GreetTool } from './tools/GreetTool.js';
241
+ import { ConfigResource } from './resources/ConfigResource.js';
242
+
243
+ const server = new McpServer({
244
+ name: '${name}',
245
+ version: '0.1.0',
246
+ transport: {
247
+ type: 'http',
248
+ port: 3000,
249
+ cors: { origin: '*' },
250
+ },
251
+ logging: { level: 'info' },
252
+ });
253
+
254
+ // Register tools
255
+ server.tool(new GreetTool());
256
+
257
+ // Register resources
258
+ server.resource(new ConfigResource());
259
+
260
+ // Start the server
261
+ server.start().then(() => {
262
+ console.log('MCP server running at http://localhost:3000/mcp');
263
+ });
264
+ `;
265
+ }
266
+ return `import { McpServer } from '@eaperezc/mcpgen';
267
+ import { GreetTool } from './tools/GreetTool.js';
268
+ import { ConfigResource } from './resources/ConfigResource.js';
269
+
270
+ const server = new McpServer({
271
+ name: '${name}',
272
+ version: '0.1.0',
273
+ logging: { level: 'info' },
274
+ });
275
+
276
+ // Register tools
277
+ server.tool(new GreetTool());
278
+
279
+ // Register resources
280
+ server.resource(new ConfigResource());
281
+
282
+ // Start the server
283
+ server.start();
284
+ `;
285
+ };
286
+ var toolsIndexTemplate = () => `export { GreetTool } from './GreetTool.js';
287
+ `;
288
+ var greetToolTemplate = () => `import { BaseTool } from '@eaperezc/mcpgen';
289
+ import { z } from 'zod';
290
+
291
+ /**
292
+ * Example tool that greets a user
293
+ */
294
+ export class GreetTool extends BaseTool {
295
+ name = 'greet';
296
+ description = 'Greets a user by name';
297
+
298
+ schema = z.object({
299
+ name: z.string().describe('The name of the person to greet'),
300
+ });
301
+
302
+ async execute(input: z.infer<typeof this.schema>) {
303
+ return {
304
+ content: {
305
+ greeting: \`Hello, \${input.name}! Welcome to your MCP server.\`,
306
+ },
307
+ };
308
+ }
309
+ }
310
+ `;
311
+ var resourcesIndexTemplate = () => `export { ConfigResource } from './ConfigResource.js';
312
+ `;
313
+ var configResourceTemplate = (name) => `import { BaseResource } from '@eaperezc/mcpgen';
314
+
315
+ /**
316
+ * Example resource that provides server configuration
317
+ */
318
+ export class ConfigResource extends BaseResource {
319
+ uri = 'config://server';
320
+ name = 'Server Configuration';
321
+ description = 'Provides server configuration information';
322
+
323
+ async read() {
324
+ return {
325
+ contents: [
326
+ this.json({
327
+ serverName: '${name}',
328
+ version: '0.1.0',
329
+ environment: process.env.NODE_ENV ?? 'development',
330
+ }),
331
+ ],
332
+ };
333
+ }
334
+ }
335
+ `;
336
+ var promptsIndexTemplate = () => `// Export your prompts here
337
+ // export { SummarizePrompt } from './SummarizePrompt.js';
338
+ `;
339
+ var testExampleTemplate = () => `import { describe, it, expect } from 'vitest';
340
+ import { createTestClient } from '@eaperezc/mcpgen/testing';
341
+ import { GreetTool } from '../src/tools/GreetTool.js';
342
+
343
+ describe('GreetTool', () => {
344
+ it('should greet the user', async () => {
345
+ const client = createTestClient();
346
+ client.registerTool(new GreetTool());
347
+
348
+ const result = await client.callTool('greet', { name: 'Alice' });
349
+
350
+ expect(result.content).toHaveProperty('greeting');
351
+ expect((result.content as { greeting: string }).greeting).toContain('Alice');
352
+ });
353
+
354
+ it('should require a name', async () => {
355
+ const client = createTestClient();
356
+ client.registerTool(new GreetTool());
357
+
358
+ await expect(client.callTool('greet', {})).rejects.toThrow();
359
+ });
360
+ });
361
+ `;
362
+ var readmeTemplate = (name, description) => `# ${name}
363
+
364
+ ${description}
365
+
366
+ ## Getting Started
367
+
368
+ ### Installation
369
+
370
+ \`\`\`bash
371
+ npm install
372
+ \`\`\`
373
+
374
+ ### Development
375
+
376
+ Run the server in development mode with hot reload:
377
+
378
+ \`\`\`bash
379
+ npm run dev
380
+ \`\`\`
381
+
382
+ ### Production
383
+
384
+ Build and run:
385
+
386
+ \`\`\`bash
387
+ npm run build
388
+ npm start
389
+ \`\`\`
390
+
391
+ ### Testing
392
+
393
+ \`\`\`bash
394
+ npm test
395
+ \`\`\`
396
+
397
+ ## Project Structure
398
+
399
+ \`\`\`
400
+ ${name}/
401
+ \u251C\u2500\u2500 src/
402
+ \u2502 \u251C\u2500\u2500 tools/ # MCP tools
403
+ \u2502 \u2502 \u2514\u2500\u2500 GreetTool.ts
404
+ \u2502 \u251C\u2500\u2500 resources/ # MCP resources
405
+ \u2502 \u2502 \u2514\u2500\u2500 ConfigResource.ts
406
+ \u2502 \u251C\u2500\u2500 prompts/ # MCP prompts
407
+ \u2502 \u2514\u2500\u2500 index.ts # Server entry point
408
+ \u251C\u2500\u2500 tests/
409
+ \u2502 \u2514\u2500\u2500 tools.test.ts
410
+ \u251C\u2500\u2500 package.json
411
+ \u2514\u2500\u2500 tsconfig.json
412
+ \`\`\`
413
+
414
+ ## Adding New Components
415
+
416
+ ### Tools
417
+
418
+ Create a new file in \`src/tools/\`:
419
+
420
+ \`\`\`typescript
421
+ import { BaseTool } from '@eaperezc/mcpgen';
422
+ import { z } from 'zod';
423
+
424
+ export class MyTool extends BaseTool {
425
+ name = 'my-tool';
426
+ description = 'Description of what this tool does';
427
+
428
+ schema = z.object({
429
+ // Define your input schema
430
+ });
431
+
432
+ async execute(input: z.infer<typeof this.schema>) {
433
+ // Implement your tool logic
434
+ return { content: { result: 'success' } };
435
+ }
436
+ }
437
+ \`\`\`
438
+
439
+ ### Resources
440
+
441
+ Create a new file in \`src/resources/\`:
442
+
443
+ \`\`\`typescript
444
+ import { BaseResource } from '@eaperezc/mcpgen';
445
+
446
+ export class MyResource extends BaseResource {
447
+ uri = 'my-resource://example';
448
+ name = 'My Resource';
449
+
450
+ async read() {
451
+ return { contents: [this.json({ data: 'example' })] };
452
+ }
453
+ }
454
+ \`\`\`
455
+
456
+ ## License
457
+
458
+ MIT
459
+ `;
460
+ var vitestConfigTemplate = () => `import { defineConfig } from 'vitest/config';
461
+
462
+ export default defineConfig({
463
+ test: {
464
+ globals: true,
465
+ environment: 'node',
466
+ },
467
+ });
468
+ `;
469
+
470
+ // src/cli/commands/init.ts
471
+ async function exists2(path) {
472
+ try {
473
+ await access(path);
474
+ return true;
475
+ } catch {
476
+ return false;
477
+ }
478
+ }
479
+ async function initProject(options) {
480
+ const {
481
+ name,
482
+ description = `An MCP server built with @eaperezc/mcpgen`,
483
+ transport = "stdio"
484
+ } = options;
485
+ const projectDir = join(process.cwd(), name);
486
+ if (await exists2(projectDir)) {
487
+ throw new Error(`Directory '${name}' already exists`);
488
+ }
489
+ console.log(`
490
+ Creating new MCP server: ${name}
491
+ `);
492
+ const dirs = [
493
+ projectDir,
494
+ join(projectDir, "src"),
495
+ join(projectDir, "src", "tools"),
496
+ join(projectDir, "src", "resources"),
497
+ join(projectDir, "src", "prompts"),
498
+ join(projectDir, "tests")
499
+ ];
500
+ for (const dir of dirs) {
501
+ await mkdir(dir, { recursive: true });
502
+ console.log(` Created: ${dir.replace(process.cwd(), ".")}`);
503
+ }
504
+ const files = [
505
+ { path: "package.json", content: packageJsonTemplate(name, description) },
506
+ { path: "tsconfig.json", content: tsconfigTemplate() },
507
+ { path: ".gitignore", content: gitignoreTemplate() },
508
+ { path: "vitest.config.ts", content: vitestConfigTemplate() },
509
+ { path: "README.md", content: readmeTemplate(name, description) },
510
+ { path: "src/index.ts", content: mainIndexTemplate(name, transport) },
511
+ { path: "src/tools/index.ts", content: toolsIndexTemplate() },
512
+ { path: "src/tools/GreetTool.ts", content: greetToolTemplate() },
513
+ { path: "src/resources/index.ts", content: resourcesIndexTemplate() },
514
+ { path: "src/resources/ConfigResource.ts", content: configResourceTemplate(name) },
515
+ { path: "src/prompts/index.ts", content: promptsIndexTemplate() },
516
+ { path: "tests/tools.test.ts", content: testExampleTemplate() }
517
+ ];
518
+ for (const file of files) {
519
+ const filePath = join(projectDir, file.path);
520
+ await writeFile(filePath, file.content);
521
+ console.log(` Created: ./${name}/${file.path}`);
522
+ }
523
+ console.log(`
524
+ \u2705 Project created successfully!
525
+
526
+ Next steps:
527
+
528
+ cd ${name}
529
+ npm install
530
+ npm run dev
531
+
532
+ ${transport === "http" ? "Server will run at http://localhost:3000/mcp" : "Server will run via stdio"}
533
+
534
+ To add new components:
535
+ - Tools: Create files in src/tools/
536
+ - Resources: Create files in src/resources/
537
+ - Prompts: Create files in src/prompts/
538
+
539
+ Happy building! \u{1F680}
540
+ `);
541
+ }
542
+
543
+ // src/cli/index.ts
544
+ var program = new Command();
545
+ program.name("mcpgen").description("CLI for building MCP servers").version("0.1.0");
546
+ program.command("init").description("Initialize a new MCP server project").argument("<name>", "Project name").option("-d, --description <desc>", "Project description").option("-t, --transport <type>", "Transport type (stdio or http)", "stdio").option("--skip-install", "Skip npm install").action(async (name, options) => {
547
+ try {
548
+ await initProject({
549
+ name,
550
+ description: options.description,
551
+ transport: options.transport,
552
+ skipInstall: options.skipInstall
553
+ });
554
+ } catch (error) {
555
+ console.error(`
556
+ \u274C Error: ${error instanceof Error ? error.message : error}
557
+ `);
558
+ process.exit(1);
559
+ }
560
+ });
561
+ program.command("make:tool").description("Create a new tool").argument("<name>", "Tool name").action(async (name) => {
562
+ try {
563
+ await generateComponent({ type: "tool", name });
564
+ } catch (error) {
565
+ console.error(`
566
+ \u274C Error: ${error instanceof Error ? error.message : error}
567
+ `);
568
+ process.exit(1);
569
+ }
570
+ });
571
+ program.command("make:resource").description("Create a new resource").argument("<name>", "Resource name").action(async (name) => {
572
+ try {
573
+ await generateComponent({ type: "resource", name });
574
+ } catch (error) {
575
+ console.error(`
576
+ \u274C Error: ${error instanceof Error ? error.message : error}
577
+ `);
578
+ process.exit(1);
579
+ }
580
+ });
581
+ program.command("make:prompt").description("Create a new prompt").argument("<name>", "Prompt name").action(async (name) => {
582
+ try {
583
+ await generateComponent({ type: "prompt", name });
584
+ } catch (error) {
585
+ console.error(`
586
+ \u274C Error: ${error instanceof Error ? error.message : error}
587
+ `);
588
+ process.exit(1);
589
+ }
590
+ });
591
+ program.addHelpText(
592
+ "after",
593
+ `
594
+ Examples:
595
+ $ mcpgen init my-mcp-server Create a new MCP server project
596
+ $ mcpgen init my-api --transport http Create with HTTP transport
597
+ $ mcpgen make:tool search Create a new tool
598
+ $ mcpgen make:resource database Create a new resource
599
+ $ mcpgen make:prompt summarize Create a new prompt
600
+ `
601
+ );
602
+ if (process.argv.length <= 2) {
603
+ const cyan = "\x1B[36m";
604
+ const dim = "\x1B[2m";
605
+ const bold = "\x1B[1m";
606
+ const reset = "\x1B[0m";
607
+ console.log(`
608
+ ${dim}+-------------------------------------+${reset}
609
+ ${dim}|${reset} ${dim}|${reset}
610
+ ${dim}|${reset} ${bold}${cyan}MCPGEN${reset} ${dim}v0.1.0${reset} ${dim}|${reset}
611
+ ${dim}|${reset} ${dim}|${reset}
612
+ ${dim}|${reset} A TypeScript framework for ${dim}|${reset}
613
+ ${dim}|${reset} building MCP servers ${dim}|${reset}
614
+ ${dim}|${reset} ${dim}|${reset}
615
+ ${dim}|${reset} Run ${cyan}mcpgen --help${reset} for commands ${dim}|${reset}
616
+ ${dim}|${reset} ${dim}|${reset}
617
+ ${dim}+-------------------------------------+${reset}
618
+ `);
619
+ } else {
620
+ program.parse();
621
+ }
622
+ //# sourceMappingURL=index.js.map
623
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/cli/commands/generate.ts","../../src/cli/templates/index.ts","../../src/cli/commands/init.ts","../../src/cli/index.ts"],"names":["exists","access","join","mkdir","writeFile"],"mappings":"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","file":"index.js","sourcesContent":["import { mkdir, writeFile, access, readFile } from 'node:fs/promises';\nimport { join, dirname } from 'node:path';\n\nexport type ComponentType = 'tool' | 'resource' | 'prompt';\n\nexport interface GenerateOptions {\n type: ComponentType;\n name: string;\n}\n\n/**\n * Convert a name to PascalCase\n */\nfunction toPascalCase(str: string): string {\n return str\n .split(/[-_\\s]+/)\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())\n .join('');\n}\n\n/**\n * Convert a name to kebab-case\n */\nfunction toKebabCase(str: string): string {\n return str\n .replace(/([a-z])([A-Z])/g, '$1-$2')\n .replace(/[\\s_]+/g, '-')\n .toLowerCase();\n}\n\n/**\n * Check if a file exists\n */\nasync function exists(path: string): Promise<boolean> {\n try {\n await access(path);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Generate tool template\n */\nfunction toolTemplate(className: string, toolName: string): string {\n return `import { BaseTool } from 'mcpkit';\nimport { z } from 'zod';\n\n/**\n * ${className} - Description of what this tool does\n */\nexport class ${className} extends BaseTool {\n name = '${toolName}';\n description = 'TODO: Add description';\n\n schema = z.object({\n // TODO: Define your input schema\n input: z.string().describe('Input parameter'),\n });\n\n async execute(input: z.infer<typeof this.schema>) {\n // TODO: Implement your tool logic\n return {\n content: {\n result: \\`Processed: \\${input.input}\\`,\n },\n };\n }\n}\n`;\n}\n\n/**\n * Generate resource template\n */\nfunction resourceTemplate(className: string, resourceName: string): string {\n return `import { BaseResource } from 'mcpkit';\n\n/**\n * ${className} - Description of what this resource provides\n */\nexport class ${className} extends BaseResource {\n uri = '${resourceName}://data';\n name = '${className}';\n description = 'TODO: Add description';\n\n async read() {\n // TODO: Implement your resource logic\n return {\n contents: [\n this.json({\n // Your data here\n example: 'data',\n }),\n ],\n };\n }\n}\n`;\n}\n\n/**\n * Generate prompt template\n */\nfunction promptTemplate(className: string, promptName: string): string {\n return `import { BasePrompt } from 'mcpkit';\nimport { z } from 'zod';\n\n/**\n * ${className} - Description of what this prompt does\n */\nexport class ${className} extends BasePrompt {\n name = '${promptName}';\n description = 'TODO: Add description';\n\n arguments = z.object({\n // TODO: Define your arguments schema\n topic: z.string().describe('The topic to discuss'),\n });\n\n async render(args: z.infer<typeof this.arguments>) {\n // TODO: Implement your prompt logic\n return {\n messages: [\n this.user(\\`Please help me with: \\${args.topic}\\`),\n ],\n };\n }\n}\n`;\n}\n\n/**\n * Update index file to export the new component\n */\nasync function updateIndexFile(indexPath: string, className: string, fileName: string): Promise<void> {\n let content = '';\n\n if (await exists(indexPath)) {\n content = await readFile(indexPath, 'utf-8');\n }\n\n const exportLine = `export { ${className} } from './${fileName}.js';`;\n\n if (!content.includes(exportLine)) {\n // Remove comments and empty lines at the start for clean exports\n const lines = content.split('\\n').filter(line =>\n line.trim() && !line.trim().startsWith('//')\n );\n lines.push(exportLine);\n content = lines.join('\\n') + '\\n';\n await writeFile(indexPath, content);\n }\n}\n\n/**\n * Generate a new component\n */\nexport async function generateComponent(options: GenerateOptions): Promise<void> {\n const { type, name } = options;\n\n const className = toPascalCase(name) + (type === 'tool' ? 'Tool' : type === 'resource' ? 'Resource' : 'Prompt');\n const fileName = className;\n const kebabName = toKebabCase(name);\n\n // Determine directory\n const typeDir = type === 'tool' ? 'tools' : type === 'resource' ? 'resources' : 'prompts';\n const srcDir = join(process.cwd(), 'src', typeDir);\n const filePath = join(srcDir, `${fileName}.ts`);\n const indexPath = join(srcDir, 'index.ts');\n\n // Check if src directory exists (are we in an mcpkit project?)\n if (!(await exists(join(process.cwd(), 'src')))) {\n throw new Error('No src/ directory found. Are you in an mcpkit project? Run \"mcpkit init\" first.');\n }\n\n // Create directory if it doesn't exist\n await mkdir(srcDir, { recursive: true });\n\n // Check if file already exists\n if (await exists(filePath)) {\n throw new Error(`${type} '${fileName}' already exists at ${filePath}`);\n }\n\n // Generate content based on type\n let content: string;\n switch (type) {\n case 'tool':\n content = toolTemplate(className, kebabName);\n break;\n case 'resource':\n content = resourceTemplate(className, kebabName);\n break;\n case 'prompt':\n content = promptTemplate(className, kebabName);\n break;\n default:\n throw new Error(`Unknown component type: ${type}`);\n }\n\n // Write file\n await writeFile(filePath, content);\n console.log(`\\n✅ Created ${type}: ${filePath.replace(process.cwd(), '.')}`);\n\n // Update index file\n await updateIndexFile(indexPath, className, fileName);\n console.log(` Updated: ${indexPath.replace(process.cwd(), '.')}`);\n\n console.log(`\nNext steps:\n\n 1. Edit src/${typeDir}/${fileName}.ts to implement your ${type}\n 2. Register it in src/index.ts:\n\n import { ${className} } from './tools/${fileName}.js';\n server.${type}(new ${className}());\n`);\n}\n","/**\n * Templates for CLI scaffolding\n */\n\nexport const packageJsonTemplate = (name: string, description: string) => `{\n \"name\": \"${name}\",\n \"version\": \"0.1.0\",\n \"description\": \"${description}\",\n \"type\": \"module\",\n \"main\": \"dist/index.js\",\n \"scripts\": {\n \"build\": \"tsc\",\n \"dev\": \"tsx watch src/index.ts\",\n \"start\": \"node dist/index.js\",\n \"test\": \"vitest run\",\n \"test:watch\": \"vitest\",\n \"lint\": \"eslint src\",\n \"typecheck\": \"tsc --noEmit\"\n },\n \"keywords\": [\"mcp\", \"model-context-protocol\"],\n \"license\": \"MIT\",\n \"dependencies\": {\n \"@eaperezc/mcpgen\": \"^0.1.0\",\n \"@modelcontextprotocol/sdk\": \"^1.11.0\",\n \"zod\": \"^3.23.8\"\n },\n \"devDependencies\": {\n \"@types/node\": \"^22.10.0\",\n \"typescript\": \"^5.7.2\",\n \"tsx\": \"^4.19.2\",\n \"vitest\": \"^2.1.8\"\n },\n \"engines\": {\n \"node\": \">=18.0.0\"\n }\n}\n`;\n\nexport const tsconfigTemplate = () => `{\n \"compilerOptions\": {\n \"target\": \"ES2022\",\n \"module\": \"ESNext\",\n \"moduleResolution\": \"bundler\",\n \"lib\": [\"ES2022\"],\n \"strict\": true,\n \"esModuleInterop\": true,\n \"skipLibCheck\": true,\n \"forceConsistentCasingInFileNames\": true,\n \"declaration\": true,\n \"outDir\": \"./dist\",\n \"rootDir\": \"./src\",\n \"resolveJsonModule\": true\n },\n \"include\": [\"src/**/*\"],\n \"exclude\": [\"node_modules\", \"dist\"]\n}\n`;\n\nexport const gitignoreTemplate = () => `# Dependencies\nnode_modules/\n\n# Build output\ndist/\n\n# Environment files\n.env\n.env.local\n.env.*.local\n\n# IDE\n.idea/\n.vscode/\n*.swp\n*.swo\n\n# OS\n.DS_Store\nThumbs.db\n\n# Logs\n*.log\n`;\n\nexport const mainIndexTemplate = (name: string, transport: 'stdio' | 'http') => {\n if (transport === 'http') {\n return `import { McpServer } from '@eaperezc/mcpgen';\nimport { GreetTool } from './tools/GreetTool.js';\nimport { ConfigResource } from './resources/ConfigResource.js';\n\nconst server = new McpServer({\n name: '${name}',\n version: '0.1.0',\n transport: {\n type: 'http',\n port: 3000,\n cors: { origin: '*' },\n },\n logging: { level: 'info' },\n});\n\n// Register tools\nserver.tool(new GreetTool());\n\n// Register resources\nserver.resource(new ConfigResource());\n\n// Start the server\nserver.start().then(() => {\n console.log('MCP server running at http://localhost:3000/mcp');\n});\n`;\n }\n\n return `import { McpServer } from '@eaperezc/mcpgen';\nimport { GreetTool } from './tools/GreetTool.js';\nimport { ConfigResource } from './resources/ConfigResource.js';\n\nconst server = new McpServer({\n name: '${name}',\n version: '0.1.0',\n logging: { level: 'info' },\n});\n\n// Register tools\nserver.tool(new GreetTool());\n\n// Register resources\nserver.resource(new ConfigResource());\n\n// Start the server\nserver.start();\n`;\n};\n\nexport const toolsIndexTemplate = () => `export { GreetTool } from './GreetTool.js';\n`;\n\nexport const greetToolTemplate = () => `import { BaseTool } from '@eaperezc/mcpgen';\nimport { z } from 'zod';\n\n/**\n * Example tool that greets a user\n */\nexport class GreetTool extends BaseTool {\n name = 'greet';\n description = 'Greets a user by name';\n\n schema = z.object({\n name: z.string().describe('The name of the person to greet'),\n });\n\n async execute(input: z.infer<typeof this.schema>) {\n return {\n content: {\n greeting: \\`Hello, \\${input.name}! Welcome to your MCP server.\\`,\n },\n };\n }\n}\n`;\n\nexport const resourcesIndexTemplate = () => `export { ConfigResource } from './ConfigResource.js';\n`;\n\nexport const configResourceTemplate = (name: string) => `import { BaseResource } from '@eaperezc/mcpgen';\n\n/**\n * Example resource that provides server configuration\n */\nexport class ConfigResource extends BaseResource {\n uri = 'config://server';\n name = 'Server Configuration';\n description = 'Provides server configuration information';\n\n async read() {\n return {\n contents: [\n this.json({\n serverName: '${name}',\n version: '0.1.0',\n environment: process.env.NODE_ENV ?? 'development',\n }),\n ],\n };\n }\n}\n`;\n\nexport const promptsIndexTemplate = () => `// Export your prompts here\n// export { SummarizePrompt } from './SummarizePrompt.js';\n`;\n\nexport const testExampleTemplate = () => `import { describe, it, expect } from 'vitest';\nimport { createTestClient } from '@eaperezc/mcpgen/testing';\nimport { GreetTool } from '../src/tools/GreetTool.js';\n\ndescribe('GreetTool', () => {\n it('should greet the user', async () => {\n const client = createTestClient();\n client.registerTool(new GreetTool());\n\n const result = await client.callTool('greet', { name: 'Alice' });\n\n expect(result.content).toHaveProperty('greeting');\n expect((result.content as { greeting: string }).greeting).toContain('Alice');\n });\n\n it('should require a name', async () => {\n const client = createTestClient();\n client.registerTool(new GreetTool());\n\n await expect(client.callTool('greet', {})).rejects.toThrow();\n });\n});\n`;\n\nexport const readmeTemplate = (name: string, description: string) => `# ${name}\n\n${description}\n\n## Getting Started\n\n### Installation\n\n\\`\\`\\`bash\nnpm install\n\\`\\`\\`\n\n### Development\n\nRun the server in development mode with hot reload:\n\n\\`\\`\\`bash\nnpm run dev\n\\`\\`\\`\n\n### Production\n\nBuild and run:\n\n\\`\\`\\`bash\nnpm run build\nnpm start\n\\`\\`\\`\n\n### Testing\n\n\\`\\`\\`bash\nnpm test\n\\`\\`\\`\n\n## Project Structure\n\n\\`\\`\\`\n${name}/\n├── src/\n│ ├── tools/ # MCP tools\n│ │ └── GreetTool.ts\n│ ├── resources/ # MCP resources\n│ │ └── ConfigResource.ts\n│ ├── prompts/ # MCP prompts\n│ └── index.ts # Server entry point\n├── tests/\n│ └── tools.test.ts\n├── package.json\n└── tsconfig.json\n\\`\\`\\`\n\n## Adding New Components\n\n### Tools\n\nCreate a new file in \\`src/tools/\\`:\n\n\\`\\`\\`typescript\nimport { BaseTool } from '@eaperezc/mcpgen';\nimport { z } from 'zod';\n\nexport class MyTool extends BaseTool {\n name = 'my-tool';\n description = 'Description of what this tool does';\n\n schema = z.object({\n // Define your input schema\n });\n\n async execute(input: z.infer<typeof this.schema>) {\n // Implement your tool logic\n return { content: { result: 'success' } };\n }\n}\n\\`\\`\\`\n\n### Resources\n\nCreate a new file in \\`src/resources/\\`:\n\n\\`\\`\\`typescript\nimport { BaseResource } from '@eaperezc/mcpgen';\n\nexport class MyResource extends BaseResource {\n uri = 'my-resource://example';\n name = 'My Resource';\n\n async read() {\n return { contents: [this.json({ data: 'example' })] };\n }\n}\n\\`\\`\\`\n\n## License\n\nMIT\n`;\n\nexport const vitestConfigTemplate = () => `import { defineConfig } from 'vitest/config';\n\nexport default defineConfig({\n test: {\n globals: true,\n environment: 'node',\n },\n});\n`;\n","import { mkdir, writeFile, access } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport {\n packageJsonTemplate,\n tsconfigTemplate,\n gitignoreTemplate,\n mainIndexTemplate,\n toolsIndexTemplate,\n greetToolTemplate,\n resourcesIndexTemplate,\n configResourceTemplate,\n promptsIndexTemplate,\n testExampleTemplate,\n readmeTemplate,\n vitestConfigTemplate,\n} from '../templates/index.js';\n\nexport interface InitOptions {\n name: string;\n description?: string;\n transport?: 'stdio' | 'http';\n skipInstall?: boolean;\n}\n\n/**\n * Check if a directory exists\n */\nasync function exists(path: string): Promise<boolean> {\n try {\n await access(path);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Initialize a new MCP server project\n */\nexport async function initProject(options: InitOptions): Promise<void> {\n const {\n name,\n description = `An MCP server built with @eaperezc/mcpgen`,\n transport = 'stdio',\n } = options;\n\n const projectDir = join(process.cwd(), name);\n\n // Check if directory already exists\n if (await exists(projectDir)) {\n throw new Error(`Directory '${name}' already exists`);\n }\n\n console.log(`\\nCreating new MCP server: ${name}\\n`);\n\n // Create directories\n const dirs = [\n projectDir,\n join(projectDir, 'src'),\n join(projectDir, 'src', 'tools'),\n join(projectDir, 'src', 'resources'),\n join(projectDir, 'src', 'prompts'),\n join(projectDir, 'tests'),\n ];\n\n for (const dir of dirs) {\n await mkdir(dir, { recursive: true });\n console.log(` Created: ${dir.replace(process.cwd(), '.')}`);\n }\n\n // Create files\n const files: Array<{ path: string; content: string }> = [\n { path: 'package.json', content: packageJsonTemplate(name, description) },\n { path: 'tsconfig.json', content: tsconfigTemplate() },\n { path: '.gitignore', content: gitignoreTemplate() },\n { path: 'vitest.config.ts', content: vitestConfigTemplate() },\n { path: 'README.md', content: readmeTemplate(name, description) },\n { path: 'src/index.ts', content: mainIndexTemplate(name, transport) },\n { path: 'src/tools/index.ts', content: toolsIndexTemplate() },\n { path: 'src/tools/GreetTool.ts', content: greetToolTemplate() },\n { path: 'src/resources/index.ts', content: resourcesIndexTemplate() },\n { path: 'src/resources/ConfigResource.ts', content: configResourceTemplate(name) },\n { path: 'src/prompts/index.ts', content: promptsIndexTemplate() },\n { path: 'tests/tools.test.ts', content: testExampleTemplate() },\n ];\n\n for (const file of files) {\n const filePath = join(projectDir, file.path);\n await writeFile(filePath, file.content);\n console.log(` Created: ./${name}/${file.path}`);\n }\n\n console.log(`\n✅ Project created successfully!\n\nNext steps:\n\n cd ${name}\n npm install\n npm run dev\n\n${transport === 'http' ? 'Server will run at http://localhost:3000/mcp' : 'Server will run via stdio'}\n\nTo add new components:\n - Tools: Create files in src/tools/\n - Resources: Create files in src/resources/\n - Prompts: Create files in src/prompts/\n\nHappy building! 🚀\n`);\n}\n","#!/usr/bin/env node\n\nimport { Command } from 'commander';\nimport { generateComponent } from './commands/generate.js';\nimport { initProject } from './commands/init.js';\n\nconst program = new Command();\n\nprogram.name('mcpgen').description('CLI for building MCP servers').version('0.1.0');\n\n// Init command\nprogram\n .command('init')\n .description('Initialize a new MCP server project')\n .argument('<name>', 'Project name')\n .option('-d, --description <desc>', 'Project description')\n .option('-t, --transport <type>', 'Transport type (stdio or http)', 'stdio')\n .option('--skip-install', 'Skip npm install')\n .action(async (name: string, options) => {\n try {\n await initProject({\n name,\n description: options.description,\n transport: options.transport as 'stdio' | 'http',\n skipInstall: options.skipInstall,\n });\n } catch (error) {\n console.error(`\\n❌ Error: ${error instanceof Error ? error.message : error}\\n`);\n process.exit(1);\n }\n });\n\n// make:tool command\nprogram\n .command('make:tool')\n .description('Create a new tool')\n .argument('<name>', 'Tool name')\n .action(async (name: string) => {\n try {\n await generateComponent({ type: 'tool', name });\n } catch (error) {\n console.error(`\\n❌ Error: ${error instanceof Error ? error.message : error}\\n`);\n process.exit(1);\n }\n });\n\n// make:resource command\nprogram\n .command('make:resource')\n .description('Create a new resource')\n .argument('<name>', 'Resource name')\n .action(async (name: string) => {\n try {\n await generateComponent({ type: 'resource', name });\n } catch (error) {\n console.error(`\\n❌ Error: ${error instanceof Error ? error.message : error}\\n`);\n process.exit(1);\n }\n });\n\n// make:prompt command\nprogram\n .command('make:prompt')\n .description('Create a new prompt')\n .argument('<name>', 'Prompt name')\n .action(async (name: string) => {\n try {\n await generateComponent({ type: 'prompt', name });\n } catch (error) {\n console.error(`\\n❌ Error: ${error instanceof Error ? error.message : error}\\n`);\n process.exit(1);\n }\n });\n\n// Add examples to help\nprogram.addHelpText(\n 'after',\n `\nExamples:\n $ mcpgen init my-mcp-server Create a new MCP server project\n $ mcpgen init my-api --transport http Create with HTTP transport\n $ mcpgen make:tool search Create a new tool\n $ mcpgen make:resource database Create a new resource\n $ mcpgen make:prompt summarize Create a new prompt\n`\n);\n\n// Show welcome message if no arguments provided\nif (process.argv.length <= 2) {\n const cyan = '\\x1b[36m';\n const dim = '\\x1b[2m';\n const bold = '\\x1b[1m';\n const reset = '\\x1b[0m';\n\n console.log(`\n${dim}+-------------------------------------+${reset}\n${dim}|${reset} ${dim}|${reset}\n${dim}|${reset} ${bold}${cyan}MCPGEN${reset} ${dim}v0.1.0${reset} ${dim}|${reset}\n${dim}|${reset} ${dim}|${reset}\n${dim}|${reset} A TypeScript framework for ${dim}|${reset}\n${dim}|${reset} building MCP servers ${dim}|${reset}\n${dim}|${reset} ${dim}|${reset}\n${dim}|${reset} Run ${cyan}mcpgen --help${reset} for commands ${dim}|${reset}\n${dim}|${reset} ${dim}|${reset}\n${dim}+-------------------------------------+${reset}\n`);\n} else {\n program.parse();\n}\n"]}