@leanmcp/cli 0.2.7 → 0.2.9
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/LICENSE +21 -21
- package/README.md +428 -428
- package/bin/leanmcp.js +3 -3
- package/dist/index.d.ts +2 -1
- package/dist/index.js +689 -122
- package/package.json +67 -66
- package/dist/index.d.mts +0 -1
- package/dist/index.mjs +0 -418
package/package.json
CHANGED
|
@@ -1,67 +1,68 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@leanmcp/cli",
|
|
3
|
-
"version": "0.2.
|
|
4
|
-
"description": "Command-line interface for scaffolding LeanMCP projects",
|
|
5
|
-
"bin": {
|
|
6
|
-
"leanmcp": "bin/leanmcp.js"
|
|
7
|
-
},
|
|
8
|
-
"type": "module",
|
|
9
|
-
"main": "dist/index.js",
|
|
10
|
-
"types": "dist/index.d.ts",
|
|
11
|
-
"exports": {
|
|
12
|
-
".": {
|
|
13
|
-
"types": "./dist/index.d.ts",
|
|
14
|
-
"import": "./dist/index.js"
|
|
15
|
-
}
|
|
16
|
-
},
|
|
17
|
-
"files": [
|
|
18
|
-
"bin",
|
|
19
|
-
"dist",
|
|
20
|
-
"README.md",
|
|
21
|
-
"LICENSE"
|
|
22
|
-
],
|
|
23
|
-
"scripts": {
|
|
24
|
-
"build": "tsup src/index.ts --format esm --dts",
|
|
25
|
-
"dev": "tsup src/index.ts --format esm --dts --watch",
|
|
26
|
-
"test": "echo \"No tests yet\" && exit 0",
|
|
27
|
-
"clean": "rimraf dist"
|
|
28
|
-
},
|
|
29
|
-
"dependencies": {
|
|
30
|
-
"@inquirer/prompts": "^7.0.1",
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
},
|
|
41
|
-
"devDependencies": {
|
|
42
|
-
"@types/fs-extra": "^11.0.4",
|
|
43
|
-
"
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
"
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
"
|
|
57
|
-
"
|
|
58
|
-
"
|
|
59
|
-
"
|
|
60
|
-
"
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
"
|
|
64
|
-
"
|
|
65
|
-
|
|
66
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "@leanmcp/cli",
|
|
3
|
+
"version": "0.2.9",
|
|
4
|
+
"description": "Command-line interface for scaffolding LeanMCP projects",
|
|
5
|
+
"bin": {
|
|
6
|
+
"leanmcp": "bin/leanmcp.js"
|
|
7
|
+
},
|
|
8
|
+
"type": "module",
|
|
9
|
+
"main": "dist/index.js",
|
|
10
|
+
"types": "dist/index.d.ts",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"import": "./dist/index.js"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"bin",
|
|
19
|
+
"dist",
|
|
20
|
+
"README.md",
|
|
21
|
+
"LICENSE"
|
|
22
|
+
],
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build": "tsup src/index.ts --format esm --dts",
|
|
25
|
+
"dev": "tsup src/index.ts --format esm --dts --watch",
|
|
26
|
+
"test": "echo \"No tests yet\" && exit 0",
|
|
27
|
+
"clean": "rimraf dist"
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@inquirer/prompts": "^7.0.1",
|
|
31
|
+
"@vitejs/plugin-react": "^4.3.0",
|
|
32
|
+
"chalk": "^5.3.0",
|
|
33
|
+
"chokidar": "^4.0.0",
|
|
34
|
+
"commander": "^12.0.0",
|
|
35
|
+
"fs-extra": "^11.2.0",
|
|
36
|
+
"glob": "^11.0.0",
|
|
37
|
+
"ora": "^8.1.0",
|
|
38
|
+
"vite": "^5.4.0",
|
|
39
|
+
"vite-plugin-singlefile": "^2.3.0"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@types/fs-extra": "^11.0.4",
|
|
43
|
+
"@types/node": "^25.0.2",
|
|
44
|
+
"rimraf": "^6.1.2"
|
|
45
|
+
},
|
|
46
|
+
"repository": {
|
|
47
|
+
"type": "git",
|
|
48
|
+
"url": "git+https://github.com/LeanMCP/leanmcp-sdk.git",
|
|
49
|
+
"directory": "packages/cli"
|
|
50
|
+
},
|
|
51
|
+
"homepage": "https://github.com/LeanMCP/leanmcp-sdk#readme",
|
|
52
|
+
"bugs": {
|
|
53
|
+
"url": "https://github.com/LeanMCP/leanmcp-sdk/issues"
|
|
54
|
+
},
|
|
55
|
+
"keywords": [
|
|
56
|
+
"mcp",
|
|
57
|
+
"model-context-protocol",
|
|
58
|
+
"cli",
|
|
59
|
+
"scaffolding",
|
|
60
|
+
"generator",
|
|
61
|
+
"typescript"
|
|
62
|
+
],
|
|
63
|
+
"author": "LeanMCP <admin@leanmcp.com>",
|
|
64
|
+
"license": "MIT",
|
|
65
|
+
"publishConfig": {
|
|
66
|
+
"access": "public"
|
|
67
|
+
}
|
|
67
68
|
}
|
package/dist/index.d.mts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
package/dist/index.mjs
DELETED
|
@@ -1,418 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
4
|
-
|
|
5
|
-
// src/index.ts
|
|
6
|
-
import { Command } from "commander";
|
|
7
|
-
import chalk from "chalk";
|
|
8
|
-
import fs from "fs-extra";
|
|
9
|
-
import path from "path";
|
|
10
|
-
import ora from "ora";
|
|
11
|
-
function capitalize(str) {
|
|
12
|
-
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
13
|
-
}
|
|
14
|
-
__name(capitalize, "capitalize");
|
|
15
|
-
var program = new Command();
|
|
16
|
-
program.name("leanmcp").description("LeanMCP CLI \u2014 create production-ready MCP servers with Streamable HTTP").version("0.1.0");
|
|
17
|
-
program.command("create <projectName>").description("Create a new LeanMCP project with Streamable HTTP transport").action(async (projectName) => {
|
|
18
|
-
const spinner = ora(`Creating project ${projectName}...`).start();
|
|
19
|
-
const targetDir = path.join(process.cwd(), projectName);
|
|
20
|
-
if (fs.existsSync(targetDir)) {
|
|
21
|
-
spinner.fail(`Folder ${projectName} already exists.`);
|
|
22
|
-
process.exit(1);
|
|
23
|
-
}
|
|
24
|
-
await fs.mkdirp(targetDir);
|
|
25
|
-
await fs.mkdirp(path.join(targetDir, "mcp"));
|
|
26
|
-
const pkg = {
|
|
27
|
-
name: projectName,
|
|
28
|
-
version: "1.0.0",
|
|
29
|
-
description: "MCP Server with Streamable HTTP Transport and LeanMCP SDK",
|
|
30
|
-
main: "dist/main.js",
|
|
31
|
-
type: "module",
|
|
32
|
-
scripts: {
|
|
33
|
-
dev: "tsx watch main.ts",
|
|
34
|
-
build: "tsc",
|
|
35
|
-
start: "node dist/main.js",
|
|
36
|
-
clean: "rm -rf dist"
|
|
37
|
-
},
|
|
38
|
-
keywords: [
|
|
39
|
-
"mcp",
|
|
40
|
-
"model-context-protocol",
|
|
41
|
-
"streamable-http",
|
|
42
|
-
"leanmcp"
|
|
43
|
-
],
|
|
44
|
-
author: "",
|
|
45
|
-
license: "MIT",
|
|
46
|
-
dependencies: {
|
|
47
|
-
"@leanmcp/core": "^0.1.0",
|
|
48
|
-
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
49
|
-
"cors": "^2.8.5",
|
|
50
|
-
"dotenv": "^16.5.0",
|
|
51
|
-
"express": "^5.1.0"
|
|
52
|
-
},
|
|
53
|
-
devDependencies: {
|
|
54
|
-
"@types/cors": "^2.8.19",
|
|
55
|
-
"@types/express": "^5.0.3",
|
|
56
|
-
"@types/node": "^20.0.0",
|
|
57
|
-
"tsx": "^4.20.3",
|
|
58
|
-
"typescript": "^5.6.3"
|
|
59
|
-
}
|
|
60
|
-
};
|
|
61
|
-
await fs.writeJSON(path.join(targetDir, "package.json"), pkg, {
|
|
62
|
-
spaces: 2
|
|
63
|
-
});
|
|
64
|
-
const tsconfig = {
|
|
65
|
-
compilerOptions: {
|
|
66
|
-
module: "ESNext",
|
|
67
|
-
target: "ES2022",
|
|
68
|
-
moduleResolution: "Node",
|
|
69
|
-
esModuleInterop: true,
|
|
70
|
-
strict: true,
|
|
71
|
-
skipLibCheck: true,
|
|
72
|
-
outDir: "dist",
|
|
73
|
-
experimentalDecorators: true,
|
|
74
|
-
emitDecoratorMetadata: true
|
|
75
|
-
},
|
|
76
|
-
include: [
|
|
77
|
-
"**/*.ts"
|
|
78
|
-
],
|
|
79
|
-
exclude: [
|
|
80
|
-
"node_modules",
|
|
81
|
-
"dist"
|
|
82
|
-
]
|
|
83
|
-
};
|
|
84
|
-
await fs.writeJSON(path.join(targetDir, "tsconfig.json"), tsconfig, {
|
|
85
|
-
spaces: 2
|
|
86
|
-
});
|
|
87
|
-
const mainTs = `import dotenv from "dotenv";
|
|
88
|
-
import { createHTTPServer, MCPServer } from "@leanmcp/core";
|
|
89
|
-
import { ExampleService } from "./mcp/example.js";
|
|
90
|
-
|
|
91
|
-
// Load environment variables
|
|
92
|
-
dotenv.config();
|
|
93
|
-
|
|
94
|
-
const PORT = Number(process.env.PORT) || 3001;
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Create and configure the MCP server
|
|
98
|
-
*/
|
|
99
|
-
function createMCPServer() {
|
|
100
|
-
const server = new MCPServer({
|
|
101
|
-
name: "${projectName}",
|
|
102
|
-
version: "1.0.0"
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
// Register your services here
|
|
106
|
-
server.registerService(new ExampleService());
|
|
107
|
-
|
|
108
|
-
return server.getServer();
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// Start the HTTP server
|
|
112
|
-
await createHTTPServer(createMCPServer, {
|
|
113
|
-
port: PORT,
|
|
114
|
-
cors: true,
|
|
115
|
-
logging: true
|
|
116
|
-
});
|
|
117
|
-
`;
|
|
118
|
-
await fs.writeFile(path.join(targetDir, "main.ts"), mainTs);
|
|
119
|
-
const exampleServiceTs = `import { Tool, Resource, Prompt, SchemaConstraint, Optional } from "@leanmcp/core";
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* Example service demonstrating LeanMCP SDK decorators
|
|
123
|
-
*
|
|
124
|
-
* This is a simple example to get you started. Add your own tools, resources, and prompts here!
|
|
125
|
-
*/
|
|
126
|
-
|
|
127
|
-
// Input schema with validation decorators
|
|
128
|
-
class CalculateInput {
|
|
129
|
-
@SchemaConstraint({ description: "First number" })
|
|
130
|
-
a!: number;
|
|
131
|
-
|
|
132
|
-
@SchemaConstraint({ description: "Second number" })
|
|
133
|
-
b!: number;
|
|
134
|
-
|
|
135
|
-
@Optional()
|
|
136
|
-
@SchemaConstraint({
|
|
137
|
-
description: "Operation to perform",
|
|
138
|
-
enum: ["add", "subtract", "multiply", "divide"],
|
|
139
|
-
default: "add"
|
|
140
|
-
})
|
|
141
|
-
operation?: string;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
export class ExampleService {
|
|
145
|
-
@Tool({
|
|
146
|
-
description: "Perform arithmetic operations with automatic schema validation",
|
|
147
|
-
inputClass: CalculateInput
|
|
148
|
-
})
|
|
149
|
-
async calculate(input: CalculateInput) {
|
|
150
|
-
let result: number;
|
|
151
|
-
|
|
152
|
-
switch (input.operation || "add") {
|
|
153
|
-
case "add":
|
|
154
|
-
result = input.a + input.b;
|
|
155
|
-
break;
|
|
156
|
-
case "subtract":
|
|
157
|
-
result = input.a - input.b;
|
|
158
|
-
break;
|
|
159
|
-
case "multiply":
|
|
160
|
-
result = input.a * input.b;
|
|
161
|
-
break;
|
|
162
|
-
case "divide":
|
|
163
|
-
if (input.b === 0) throw new Error("Cannot divide by zero");
|
|
164
|
-
result = input.a / input.b;
|
|
165
|
-
break;
|
|
166
|
-
default:
|
|
167
|
-
throw new Error("Invalid operation");
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
return {
|
|
171
|
-
content: [{
|
|
172
|
-
type: "text" as const,
|
|
173
|
-
text: JSON.stringify({
|
|
174
|
-
operation: input.operation || "add",
|
|
175
|
-
operands: { a: input.a, b: input.b },
|
|
176
|
-
result
|
|
177
|
-
}, null, 2)
|
|
178
|
-
}]
|
|
179
|
-
};
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
@Tool({ description: "Echo a message back" })
|
|
183
|
-
async echo(input: { message: string }) {
|
|
184
|
-
return {
|
|
185
|
-
content: [{
|
|
186
|
-
type: "text" as const,
|
|
187
|
-
text: JSON.stringify({
|
|
188
|
-
echoed: input.message,
|
|
189
|
-
timestamp: new Date().toISOString()
|
|
190
|
-
}, null, 2)
|
|
191
|
-
}]
|
|
192
|
-
};
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
@Resource({ description: "Get server information" })
|
|
196
|
-
async serverInfo() {
|
|
197
|
-
return {
|
|
198
|
-
contents: [{
|
|
199
|
-
uri: "server://info",
|
|
200
|
-
mimeType: "application/json",
|
|
201
|
-
text: JSON.stringify({
|
|
202
|
-
name: "${projectName}",
|
|
203
|
-
version: "1.0.0",
|
|
204
|
-
uptime: process.uptime()
|
|
205
|
-
}, null, 2)
|
|
206
|
-
}]
|
|
207
|
-
};
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
@Prompt({ description: "Generate a greeting prompt" })
|
|
211
|
-
async greeting(args: { name?: string }) {
|
|
212
|
-
return {
|
|
213
|
-
messages: [{
|
|
214
|
-
role: "user" as const,
|
|
215
|
-
content: {
|
|
216
|
-
type: "text" as const,
|
|
217
|
-
text: \`Hello \${args.name || 'there'}! Welcome to ${projectName}.\`
|
|
218
|
-
}
|
|
219
|
-
}]
|
|
220
|
-
};
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
`;
|
|
224
|
-
await fs.writeFile(path.join(targetDir, "mcp", "example.ts"), exampleServiceTs);
|
|
225
|
-
const gitignore = `node_modules
|
|
226
|
-
dist
|
|
227
|
-
.env
|
|
228
|
-
.env.local
|
|
229
|
-
*.log
|
|
230
|
-
`;
|
|
231
|
-
const env = `# Server Configuration
|
|
232
|
-
PORT=3001
|
|
233
|
-
NODE_ENV=development
|
|
234
|
-
|
|
235
|
-
# Add your environment variables here
|
|
236
|
-
`;
|
|
237
|
-
await fs.writeFile(path.join(targetDir, ".gitignore"), gitignore);
|
|
238
|
-
await fs.writeFile(path.join(targetDir, ".env"), env);
|
|
239
|
-
const readme = `# ${projectName}
|
|
240
|
-
|
|
241
|
-
MCP Server with Streamable HTTP Transport built with LeanMCP SDK
|
|
242
|
-
|
|
243
|
-
## Quick Start
|
|
244
|
-
|
|
245
|
-
\`\`\`bash
|
|
246
|
-
# Install dependencies
|
|
247
|
-
npm install
|
|
248
|
-
|
|
249
|
-
# Start development server (hot reload)
|
|
250
|
-
npm run dev
|
|
251
|
-
|
|
252
|
-
# Build for production
|
|
253
|
-
npm run build
|
|
254
|
-
|
|
255
|
-
# Run production server
|
|
256
|
-
npm start
|
|
257
|
-
\`\`\`
|
|
258
|
-
|
|
259
|
-
## Project Structure
|
|
260
|
-
|
|
261
|
-
\`\`\`
|
|
262
|
-
${projectName}/
|
|
263
|
-
\u251C\u2500\u2500 main.ts # Server entry point
|
|
264
|
-
\u251C\u2500\u2500 mcp/
|
|
265
|
-
\u2502 \u2514\u2500\u2500 example.ts # Example service
|
|
266
|
-
\u251C\u2500\u2500 .env # Environment variables
|
|
267
|
-
\u2514\u2500\u2500 package.json
|
|
268
|
-
\`\`\`
|
|
269
|
-
|
|
270
|
-
## Adding New Services
|
|
271
|
-
|
|
272
|
-
Create a new service file in \`mcp/\`:
|
|
273
|
-
|
|
274
|
-
\`\`\`typescript
|
|
275
|
-
import { Tool } from "@leanmcp/core";
|
|
276
|
-
|
|
277
|
-
export class MyService {
|
|
278
|
-
@Tool({ description: "My awesome tool" })
|
|
279
|
-
async myTool(input: { message: string }) {
|
|
280
|
-
return {
|
|
281
|
-
content: [{
|
|
282
|
-
type: "text",
|
|
283
|
-
text: \`You said: \${input.message}\`
|
|
284
|
-
}]
|
|
285
|
-
};
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
\`\`\`
|
|
289
|
-
|
|
290
|
-
Then register it in \`main.ts\`:
|
|
291
|
-
|
|
292
|
-
\`\`\`typescript
|
|
293
|
-
import { MyService } from "./mcp/my-service.js";
|
|
294
|
-
server.registerService(new MyService());
|
|
295
|
-
\`\`\`
|
|
296
|
-
|
|
297
|
-
## Testing with MCP Inspector
|
|
298
|
-
|
|
299
|
-
\`\`\`bash
|
|
300
|
-
npx @modelcontextprotocol/inspector http://localhost:3001/mcp
|
|
301
|
-
\`\`\`
|
|
302
|
-
|
|
303
|
-
## License
|
|
304
|
-
|
|
305
|
-
MIT
|
|
306
|
-
`;
|
|
307
|
-
await fs.writeFile(path.join(targetDir, "README.md"), readme);
|
|
308
|
-
spinner.succeed(`Project ${projectName} created!`);
|
|
309
|
-
console.log(chalk.green("\\nSuccess! Your MCP server is ready.\\n"));
|
|
310
|
-
console.log(chalk.cyan("Next steps:"));
|
|
311
|
-
console.log(chalk.gray(` cd ${projectName}`));
|
|
312
|
-
console.log(chalk.gray(` npm install`));
|
|
313
|
-
console.log(chalk.gray(` npm run dev`));
|
|
314
|
-
console.log(chalk.gray(`\\nServer will run on http://localhost:3001`));
|
|
315
|
-
});
|
|
316
|
-
program.command("add <serviceName>").description("Add a new MCP service to your project").action(async (serviceName) => {
|
|
317
|
-
const cwd = process.cwd();
|
|
318
|
-
const mcpDir = path.join(cwd, "mcp");
|
|
319
|
-
if (!fs.existsSync(path.join(cwd, "main.ts"))) {
|
|
320
|
-
console.error(chalk.red("ERROR: Not a LeanMCP project (main.ts missing)."));
|
|
321
|
-
process.exit(1);
|
|
322
|
-
}
|
|
323
|
-
await fs.mkdirp(mcpDir);
|
|
324
|
-
const serviceFile = path.join(mcpDir, `${serviceName}.ts`);
|
|
325
|
-
if (fs.existsSync(serviceFile)) {
|
|
326
|
-
console.error(chalk.red(`ERROR: Service ${serviceName} already exists.`));
|
|
327
|
-
process.exit(1);
|
|
328
|
-
}
|
|
329
|
-
const indexTs = `import { Tool, Resource, Prompt, Optional, SchemaConstraint } from "@leanmcp/core";
|
|
330
|
-
|
|
331
|
-
// Input schema for greeting
|
|
332
|
-
class GreetInput {
|
|
333
|
-
@SchemaConstraint({
|
|
334
|
-
description: "Name to greet",
|
|
335
|
-
minLength: 1
|
|
336
|
-
})
|
|
337
|
-
name!: string;
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
/**
|
|
341
|
-
* ${capitalize(serviceName)} Service
|
|
342
|
-
*
|
|
343
|
-
* This service demonstrates the three types of MCP primitives:
|
|
344
|
-
* - Tools: Callable functions (like API endpoints)
|
|
345
|
-
* - Prompts: Reusable prompt templates
|
|
346
|
-
* - Resources: Data sources/endpoints
|
|
347
|
-
*/
|
|
348
|
-
export class ${capitalize(serviceName)}Service {
|
|
349
|
-
// TOOL - Callable function
|
|
350
|
-
// Tool name: "greet" (from function name)
|
|
351
|
-
@Tool({
|
|
352
|
-
description: "Greet a user by name",
|
|
353
|
-
inputClass: GreetInput
|
|
354
|
-
})
|
|
355
|
-
greet(args: GreetInput) {
|
|
356
|
-
return { message: \`Hello, \${args.name}! from ${serviceName}\` };
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
// PROMPT - Prompt template
|
|
360
|
-
// Prompt name: "welcomePrompt" (from function name)
|
|
361
|
-
@Prompt({ description: "Welcome message prompt template" })
|
|
362
|
-
welcomePrompt(args: { userName?: string }) {
|
|
363
|
-
return {
|
|
364
|
-
messages: [
|
|
365
|
-
{
|
|
366
|
-
role: "user",
|
|
367
|
-
content: {
|
|
368
|
-
type: "text",
|
|
369
|
-
text: \`Welcome \${args.userName || 'user'}! How can I help you with ${serviceName}?\`
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
]
|
|
373
|
-
};
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
// RESOURCE - Data endpoint
|
|
377
|
-
// Resource URI auto-generated from class and method name
|
|
378
|
-
@Resource({ description: "${capitalize(serviceName)} service status" })
|
|
379
|
-
getStatus() {
|
|
380
|
-
return {
|
|
381
|
-
service: "${serviceName}",
|
|
382
|
-
status: "active",
|
|
383
|
-
timestamp: new Date().toISOString()
|
|
384
|
-
};
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
`;
|
|
388
|
-
await fs.writeFile(serviceFile, indexTs);
|
|
389
|
-
const mainTsPath = path.join(cwd, "main.ts");
|
|
390
|
-
let mainTsContent = await fs.readFile(mainTsPath, "utf-8");
|
|
391
|
-
const serviceClassName = `${capitalize(serviceName)}Service`;
|
|
392
|
-
const importStatement = `import { ${serviceClassName} } from "./mcp/${serviceName}.js";`;
|
|
393
|
-
const registerStatement = ` server.registerService(new ${serviceClassName}());`;
|
|
394
|
-
const lastImportMatch = mainTsContent.match(/import .* from .*;\n/g);
|
|
395
|
-
if (lastImportMatch) {
|
|
396
|
-
const lastImport = lastImportMatch[lastImportMatch.length - 1];
|
|
397
|
-
const lastImportIndex = mainTsContent.lastIndexOf(lastImport);
|
|
398
|
-
const afterLastImport = lastImportIndex + lastImport.length;
|
|
399
|
-
mainTsContent = mainTsContent.slice(0, afterLastImport) + importStatement + "\n" + mainTsContent.slice(afterLastImport);
|
|
400
|
-
}
|
|
401
|
-
const registerPattern = /server\.registerService\(new \w+\(\)\);/g;
|
|
402
|
-
const matches = [
|
|
403
|
-
...mainTsContent.matchAll(registerPattern)
|
|
404
|
-
];
|
|
405
|
-
if (matches.length > 0) {
|
|
406
|
-
const lastMatch = matches[matches.length - 1];
|
|
407
|
-
const insertPosition = lastMatch.index + lastMatch[0].length;
|
|
408
|
-
mainTsContent = mainTsContent.slice(0, insertPosition) + "\n" + registerStatement + mainTsContent.slice(insertPosition);
|
|
409
|
-
}
|
|
410
|
-
await fs.writeFile(mainTsPath, mainTsContent);
|
|
411
|
-
console.log(chalk.green(`\\nCreated new service: ${chalk.bold(serviceName)}`));
|
|
412
|
-
console.log(chalk.gray(` File: mcp/${serviceName}.ts`));
|
|
413
|
-
console.log(chalk.gray(` Tool: greet`));
|
|
414
|
-
console.log(chalk.gray(` Prompt: welcomePrompt`));
|
|
415
|
-
console.log(chalk.gray(` Resource: getStatus`));
|
|
416
|
-
console.log(chalk.green(`\\nService automatically registered in main.ts!`));
|
|
417
|
-
});
|
|
418
|
-
program.parse();
|