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