mcp-new 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/LICENSE +21 -0
- package/README.md +184 -0
- package/bin/mcp-new.js +3 -0
- package/dist/chunk-QRUHMGU5.js +1540 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +25 -0
- package/dist/index.d.ts +516 -0
- package/dist/index.js +351 -0
- package/package.json +73 -0
- package/templates/python/.env.example +8 -0
- package/templates/python/.gitignore.ejs +37 -0
- package/templates/python/README.md.ejs +78 -0
- package/templates/python/pyproject.toml.ejs +20 -0
- package/templates/python/requirements.txt.ejs +1 -0
- package/templates/python/src/__init__.py.ejs +3 -0
- package/templates/python/src/server.py.ejs +98 -0
- package/templates/python/src/tools/__init__.py.ejs +1 -0
- package/templates/python/src/tools/example_tool.py.ejs +47 -0
- package/templates/typescript/.env.example +8 -0
- package/templates/typescript/.gitignore.ejs +22 -0
- package/templates/typescript/README.md.ejs +78 -0
- package/templates/typescript/package.json.ejs +29 -0
- package/templates/typescript/src/index.ts.ejs +121 -0
- package/templates/typescript/src/tools/example-tool.ts.ejs +36 -0
- package/templates/typescript/tsconfig.json.ejs +19 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
import {
|
|
2
|
+
BaseGenerator,
|
|
3
|
+
OpenAPIGenerator,
|
|
4
|
+
PromptGenerator,
|
|
5
|
+
WizardGenerator,
|
|
6
|
+
addToolCommand,
|
|
7
|
+
copyDir,
|
|
8
|
+
copyFile,
|
|
9
|
+
createCommand,
|
|
10
|
+
createGeneratorContext,
|
|
11
|
+
createInitialCommit,
|
|
12
|
+
createSpinner,
|
|
13
|
+
endpointToMCPTool,
|
|
14
|
+
ensureDir,
|
|
15
|
+
exists,
|
|
16
|
+
generateFromOpenAPI,
|
|
17
|
+
generateFromPrompt,
|
|
18
|
+
generateFromWizard,
|
|
19
|
+
getGitUser,
|
|
20
|
+
getTemplateDir,
|
|
21
|
+
initCommand,
|
|
22
|
+
initGitRepository,
|
|
23
|
+
isDirectory,
|
|
24
|
+
isGitInstalled,
|
|
25
|
+
isInsideGitRepository,
|
|
26
|
+
logger,
|
|
27
|
+
parseAndValidate,
|
|
28
|
+
parseOpenAPISpec,
|
|
29
|
+
projectNameRegex,
|
|
30
|
+
promptAddResources,
|
|
31
|
+
promptAddTools,
|
|
32
|
+
promptIncludeExampleTool,
|
|
33
|
+
promptLanguage,
|
|
34
|
+
promptMultipleResources,
|
|
35
|
+
promptMultipleTools,
|
|
36
|
+
promptProjectDescription,
|
|
37
|
+
promptProjectName,
|
|
38
|
+
promptResourceConfig,
|
|
39
|
+
promptToolConfig,
|
|
40
|
+
promptTransport,
|
|
41
|
+
readDir,
|
|
42
|
+
readFile,
|
|
43
|
+
remove,
|
|
44
|
+
renderTemplate,
|
|
45
|
+
renderTemplateToFile,
|
|
46
|
+
resolveOutputPath,
|
|
47
|
+
runQuickWizard,
|
|
48
|
+
runWizard,
|
|
49
|
+
safeParseAndValidate,
|
|
50
|
+
selectEndpoints,
|
|
51
|
+
validateFilePath,
|
|
52
|
+
validateProjectName,
|
|
53
|
+
validateToolName,
|
|
54
|
+
validateUrl,
|
|
55
|
+
walkDir,
|
|
56
|
+
withSpinner,
|
|
57
|
+
writeFile
|
|
58
|
+
} from "./chunk-QRUHMGU5.js";
|
|
59
|
+
|
|
60
|
+
// src/types/config.ts
|
|
61
|
+
import { z } from "zod";
|
|
62
|
+
var LanguageSchema = z.enum(["typescript", "python"]);
|
|
63
|
+
var TransportSchema = z.enum(["stdio", "sse"]);
|
|
64
|
+
var ToolParameterSchema = z.object({
|
|
65
|
+
name: z.string(),
|
|
66
|
+
type: z.enum(["string", "number", "boolean", "object", "array"]),
|
|
67
|
+
description: z.string(),
|
|
68
|
+
required: z.boolean().default(true)
|
|
69
|
+
});
|
|
70
|
+
var ToolConfigSchema = z.object({
|
|
71
|
+
name: z.string(),
|
|
72
|
+
description: z.string(),
|
|
73
|
+
parameters: z.array(ToolParameterSchema).default([])
|
|
74
|
+
});
|
|
75
|
+
var ResourceConfigSchema = z.object({
|
|
76
|
+
name: z.string(),
|
|
77
|
+
uri: z.string(),
|
|
78
|
+
description: z.string(),
|
|
79
|
+
mimeType: z.string().optional()
|
|
80
|
+
});
|
|
81
|
+
var ProjectConfigSchema = z.object({
|
|
82
|
+
name: z.string().min(1, "Project name is required"),
|
|
83
|
+
description: z.string().default(""),
|
|
84
|
+
language: LanguageSchema,
|
|
85
|
+
transport: TransportSchema,
|
|
86
|
+
tools: z.array(ToolConfigSchema).default([]),
|
|
87
|
+
resources: z.array(ResourceConfigSchema).default([]),
|
|
88
|
+
includeExampleTool: z.boolean().default(true),
|
|
89
|
+
skipInstall: z.boolean().default(false),
|
|
90
|
+
initGit: z.boolean().default(true)
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
// src/parsers/swagger.ts
|
|
94
|
+
import YAML from "yaml";
|
|
95
|
+
async function parseSwaggerSpec(content) {
|
|
96
|
+
let spec;
|
|
97
|
+
try {
|
|
98
|
+
spec = YAML.parse(content);
|
|
99
|
+
} catch {
|
|
100
|
+
throw new Error("Failed to parse Swagger specification.");
|
|
101
|
+
}
|
|
102
|
+
if (!spec.swagger || !spec.swagger.startsWith("2.")) {
|
|
103
|
+
throw new Error("Invalid Swagger specification. Expected swagger version 2.x");
|
|
104
|
+
}
|
|
105
|
+
const endpoints = [];
|
|
106
|
+
for (const [path, pathItem] of Object.entries(spec.paths)) {
|
|
107
|
+
const methods = ["get", "post", "put", "delete", "patch"];
|
|
108
|
+
for (const method of methods) {
|
|
109
|
+
const operation = pathItem[method];
|
|
110
|
+
if (!operation) continue;
|
|
111
|
+
const parameters = [];
|
|
112
|
+
if (operation.parameters) {
|
|
113
|
+
for (const param of operation.parameters) {
|
|
114
|
+
if (param.in === "body" && param.schema) {
|
|
115
|
+
const bodyParams = extractSwaggerBodyParams(param.schema, spec.definitions);
|
|
116
|
+
parameters.push(...bodyParams);
|
|
117
|
+
} else {
|
|
118
|
+
parameters.push({
|
|
119
|
+
name: param.name,
|
|
120
|
+
in: param.in,
|
|
121
|
+
type: param.type || "string",
|
|
122
|
+
description: param.description || "",
|
|
123
|
+
required: param.required || false
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
endpoints.push({
|
|
129
|
+
path,
|
|
130
|
+
method: method.toUpperCase(),
|
|
131
|
+
operationId: operation.operationId || "",
|
|
132
|
+
summary: operation.summary || "",
|
|
133
|
+
description: operation.description || "",
|
|
134
|
+
parameters,
|
|
135
|
+
tags: operation.tags || []
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return endpoints;
|
|
140
|
+
}
|
|
141
|
+
function extractSwaggerBodyParams(schema, definitions) {
|
|
142
|
+
const parameters = [];
|
|
143
|
+
if (schema.$ref && definitions) {
|
|
144
|
+
const refName = schema.$ref.replace("#/definitions/", "");
|
|
145
|
+
const resolved = definitions[refName];
|
|
146
|
+
if (resolved) {
|
|
147
|
+
schema = resolved;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
if (schema.properties) {
|
|
151
|
+
for (const [name, propSchema] of Object.entries(schema.properties)) {
|
|
152
|
+
let resolvedProp = propSchema;
|
|
153
|
+
if (propSchema.$ref && definitions) {
|
|
154
|
+
const refName = propSchema.$ref.replace("#/definitions/", "");
|
|
155
|
+
resolvedProp = definitions[refName] || propSchema;
|
|
156
|
+
}
|
|
157
|
+
parameters.push({
|
|
158
|
+
name,
|
|
159
|
+
in: "body",
|
|
160
|
+
type: resolvedProp.type || "string",
|
|
161
|
+
description: "",
|
|
162
|
+
required: schema.required?.includes(name) || false
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return parameters;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// src/parsers/postman.ts
|
|
170
|
+
async function parsePostmanCollection(content) {
|
|
171
|
+
let collection;
|
|
172
|
+
try {
|
|
173
|
+
collection = JSON.parse(content);
|
|
174
|
+
} catch {
|
|
175
|
+
throw new Error("Failed to parse Postman collection. Ensure it is valid JSON.");
|
|
176
|
+
}
|
|
177
|
+
if (!collection.info?.schema?.includes("postman")) {
|
|
178
|
+
throw new Error("Invalid Postman collection format.");
|
|
179
|
+
}
|
|
180
|
+
const endpoints = [];
|
|
181
|
+
extractItemsRecursively(collection.item, endpoints);
|
|
182
|
+
return endpoints;
|
|
183
|
+
}
|
|
184
|
+
function extractItemsRecursively(items, endpoints) {
|
|
185
|
+
for (const item of items) {
|
|
186
|
+
if (item.item) {
|
|
187
|
+
extractItemsRecursively(item.item, endpoints);
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
if (item.request) {
|
|
191
|
+
const endpoint = parsePostmanRequest(item.name, item.request);
|
|
192
|
+
if (endpoint) {
|
|
193
|
+
endpoints.push(endpoint);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
function parsePostmanRequest(name, request) {
|
|
199
|
+
const parameters = [];
|
|
200
|
+
let path = "/";
|
|
201
|
+
if (typeof request.url === "string") {
|
|
202
|
+
try {
|
|
203
|
+
const url = new URL(request.url);
|
|
204
|
+
path = url.pathname;
|
|
205
|
+
} catch {
|
|
206
|
+
path = request.url;
|
|
207
|
+
}
|
|
208
|
+
} else if (request.url) {
|
|
209
|
+
path = "/" + (request.url.path?.join("/") || "");
|
|
210
|
+
if (request.url.query) {
|
|
211
|
+
for (const query of request.url.query) {
|
|
212
|
+
if (query.disabled) continue;
|
|
213
|
+
parameters.push({
|
|
214
|
+
name: query.key,
|
|
215
|
+
in: "query",
|
|
216
|
+
type: "string",
|
|
217
|
+
description: query.description || "",
|
|
218
|
+
required: false
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
if (request.url.variable) {
|
|
223
|
+
for (const variable of request.url.variable) {
|
|
224
|
+
parameters.push({
|
|
225
|
+
name: variable.key,
|
|
226
|
+
in: "path",
|
|
227
|
+
type: "string",
|
|
228
|
+
description: variable.description || "",
|
|
229
|
+
required: true
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
if (request.body) {
|
|
235
|
+
if (request.body.mode === "urlencoded" && request.body.urlencoded) {
|
|
236
|
+
for (const param of request.body.urlencoded) {
|
|
237
|
+
parameters.push({
|
|
238
|
+
name: param.key,
|
|
239
|
+
in: "body",
|
|
240
|
+
type: param.type || "string",
|
|
241
|
+
description: param.description || "",
|
|
242
|
+
required: false
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
} else if (request.body.mode === "formdata" && request.body.formdata) {
|
|
246
|
+
for (const param of request.body.formdata) {
|
|
247
|
+
parameters.push({
|
|
248
|
+
name: param.key,
|
|
249
|
+
in: "body",
|
|
250
|
+
type: param.type || "string",
|
|
251
|
+
description: param.description || "",
|
|
252
|
+
required: false
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
} else if (request.body.mode === "raw" && request.body.raw) {
|
|
256
|
+
try {
|
|
257
|
+
const body = JSON.parse(request.body.raw);
|
|
258
|
+
if (typeof body === "object" && body !== null) {
|
|
259
|
+
for (const key of Object.keys(body)) {
|
|
260
|
+
parameters.push({
|
|
261
|
+
name: key,
|
|
262
|
+
in: "body",
|
|
263
|
+
type: typeof body[key],
|
|
264
|
+
description: "",
|
|
265
|
+
required: false
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
} catch {
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
return {
|
|
274
|
+
path,
|
|
275
|
+
method: request.method.toUpperCase(),
|
|
276
|
+
operationId: nameToOperationId(name),
|
|
277
|
+
summary: name,
|
|
278
|
+
description: request.description || "",
|
|
279
|
+
parameters,
|
|
280
|
+
tags: []
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
function nameToOperationId(name) {
|
|
284
|
+
return name.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
|
|
285
|
+
}
|
|
286
|
+
export {
|
|
287
|
+
BaseGenerator,
|
|
288
|
+
LanguageSchema,
|
|
289
|
+
OpenAPIGenerator,
|
|
290
|
+
ProjectConfigSchema,
|
|
291
|
+
PromptGenerator,
|
|
292
|
+
ResourceConfigSchema,
|
|
293
|
+
ToolConfigSchema,
|
|
294
|
+
ToolParameterSchema,
|
|
295
|
+
TransportSchema,
|
|
296
|
+
WizardGenerator,
|
|
297
|
+
addToolCommand,
|
|
298
|
+
copyDir,
|
|
299
|
+
copyFile,
|
|
300
|
+
createCommand,
|
|
301
|
+
createGeneratorContext,
|
|
302
|
+
createInitialCommit,
|
|
303
|
+
createSpinner,
|
|
304
|
+
endpointToMCPTool,
|
|
305
|
+
ensureDir,
|
|
306
|
+
exists,
|
|
307
|
+
generateFromOpenAPI,
|
|
308
|
+
generateFromPrompt,
|
|
309
|
+
generateFromWizard,
|
|
310
|
+
getGitUser,
|
|
311
|
+
getTemplateDir,
|
|
312
|
+
initCommand,
|
|
313
|
+
initGitRepository,
|
|
314
|
+
isDirectory,
|
|
315
|
+
isGitInstalled,
|
|
316
|
+
isInsideGitRepository,
|
|
317
|
+
logger,
|
|
318
|
+
parseAndValidate,
|
|
319
|
+
parseOpenAPISpec,
|
|
320
|
+
parsePostmanCollection,
|
|
321
|
+
parseSwaggerSpec,
|
|
322
|
+
projectNameRegex,
|
|
323
|
+
promptAddResources,
|
|
324
|
+
promptAddTools,
|
|
325
|
+
promptIncludeExampleTool,
|
|
326
|
+
promptLanguage,
|
|
327
|
+
promptMultipleResources,
|
|
328
|
+
promptMultipleTools,
|
|
329
|
+
promptProjectDescription,
|
|
330
|
+
promptProjectName,
|
|
331
|
+
promptResourceConfig,
|
|
332
|
+
promptToolConfig,
|
|
333
|
+
promptTransport,
|
|
334
|
+
readDir,
|
|
335
|
+
readFile,
|
|
336
|
+
remove,
|
|
337
|
+
renderTemplate,
|
|
338
|
+
renderTemplateToFile,
|
|
339
|
+
resolveOutputPath,
|
|
340
|
+
runQuickWizard,
|
|
341
|
+
runWizard,
|
|
342
|
+
safeParseAndValidate,
|
|
343
|
+
selectEndpoints,
|
|
344
|
+
validateFilePath,
|
|
345
|
+
validateProjectName,
|
|
346
|
+
validateToolName,
|
|
347
|
+
validateUrl,
|
|
348
|
+
walkDir,
|
|
349
|
+
withSpinner,
|
|
350
|
+
writeFile
|
|
351
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "mcp-new",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "CLI generator for MCP servers. Like create-react-app, but for MCP.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"bin": {
|
|
9
|
+
"mcp-new": "./bin/mcp-new.js"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"dist",
|
|
13
|
+
"bin",
|
|
14
|
+
"templates"
|
|
15
|
+
],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"dev": "tsup src/index.ts --watch --format esm",
|
|
18
|
+
"build": "tsup src/index.ts src/cli.ts --format esm --dts --clean",
|
|
19
|
+
"test": "vitest",
|
|
20
|
+
"test:run": "vitest run",
|
|
21
|
+
"lint": "eslint src --ext .ts",
|
|
22
|
+
"lint:fix": "eslint src --ext .ts --fix",
|
|
23
|
+
"format": "prettier --write \"src/**/*.ts\"",
|
|
24
|
+
"prepublishOnly": "npm run build"
|
|
25
|
+
},
|
|
26
|
+
"keywords": [
|
|
27
|
+
"mcp",
|
|
28
|
+
"model-context-protocol",
|
|
29
|
+
"cli",
|
|
30
|
+
"generator",
|
|
31
|
+
"anthropic",
|
|
32
|
+
"claude"
|
|
33
|
+
],
|
|
34
|
+
"author": "Dinmukhanbet Aizharykov <dimashaijarikov@gmail.com>",
|
|
35
|
+
"license": "MIT",
|
|
36
|
+
"homepage": "https://github.com/d1maash/mcp-new#readme",
|
|
37
|
+
"bugs": {
|
|
38
|
+
"url": "https://github.com/d1maash/mcp-new/issues"
|
|
39
|
+
},
|
|
40
|
+
"repository": {
|
|
41
|
+
"type": "git",
|
|
42
|
+
"url": "git+https://github.com/d1maash/mcp-new.git"
|
|
43
|
+
},
|
|
44
|
+
"engines": {
|
|
45
|
+
"node": ">=18.0.0"
|
|
46
|
+
},
|
|
47
|
+
"dependencies": {
|
|
48
|
+
"@anthropic-ai/sdk": "^0.30.0",
|
|
49
|
+
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
50
|
+
"chalk": "^5.3.0",
|
|
51
|
+
"commander": "^12.0.0",
|
|
52
|
+
"ejs": "^3.1.10",
|
|
53
|
+
"execa": "^8.0.0",
|
|
54
|
+
"fs-extra": "^11.2.0",
|
|
55
|
+
"inquirer": "^9.2.0",
|
|
56
|
+
"ora": "^8.0.0",
|
|
57
|
+
"yaml": "^2.4.0",
|
|
58
|
+
"zod": "^3.23.0"
|
|
59
|
+
},
|
|
60
|
+
"devDependencies": {
|
|
61
|
+
"@types/ejs": "^3.1.0",
|
|
62
|
+
"@types/fs-extra": "^11.0.0",
|
|
63
|
+
"@types/inquirer": "^9.0.0",
|
|
64
|
+
"@types/node": "^20.0.0",
|
|
65
|
+
"@typescript-eslint/eslint-plugin": "^7.0.0",
|
|
66
|
+
"@typescript-eslint/parser": "^7.0.0",
|
|
67
|
+
"eslint": "^8.57.0",
|
|
68
|
+
"prettier": "^3.2.0",
|
|
69
|
+
"tsup": "^8.0.0",
|
|
70
|
+
"typescript": "^5.4.0",
|
|
71
|
+
"vitest": "^1.6.0"
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# Virtual environments
|
|
7
|
+
venv/
|
|
8
|
+
.venv/
|
|
9
|
+
env/
|
|
10
|
+
.env/
|
|
11
|
+
|
|
12
|
+
# Environment variables
|
|
13
|
+
.env
|
|
14
|
+
.env.local
|
|
15
|
+
|
|
16
|
+
# Distribution / packaging
|
|
17
|
+
dist/
|
|
18
|
+
build/
|
|
19
|
+
*.egg-info/
|
|
20
|
+
|
|
21
|
+
# IDE
|
|
22
|
+
.idea/
|
|
23
|
+
.vscode/
|
|
24
|
+
*.swp
|
|
25
|
+
|
|
26
|
+
# OS
|
|
27
|
+
.DS_Store
|
|
28
|
+
Thumbs.db
|
|
29
|
+
|
|
30
|
+
# Logs
|
|
31
|
+
*.log
|
|
32
|
+
|
|
33
|
+
# pytest
|
|
34
|
+
.pytest_cache/
|
|
35
|
+
|
|
36
|
+
# mypy
|
|
37
|
+
.mypy_cache/
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# <%= name %>
|
|
2
|
+
|
|
3
|
+
<%= description || 'MCP Server generated by create-mcp-server' %>
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install -e .
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Or using requirements.txt:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
pip install -r requirements.txt
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Usage
|
|
18
|
+
|
|
19
|
+
### Running the server
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
python -m src.server
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Or if installed:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
<%= name %>
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Configuration
|
|
32
|
+
|
|
33
|
+
### Claude Desktop
|
|
34
|
+
|
|
35
|
+
Add this to your Claude Desktop config file:
|
|
36
|
+
|
|
37
|
+
**macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
38
|
+
**Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
|
|
39
|
+
|
|
40
|
+
```json
|
|
41
|
+
{
|
|
42
|
+
"mcpServers": {
|
|
43
|
+
"<%= name %>": {
|
|
44
|
+
"command": "python",
|
|
45
|
+
"args": ["-m", "src.server"],
|
|
46
|
+
"cwd": "<path-to-project>"
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Available Tools
|
|
53
|
+
|
|
54
|
+
<% if (includeExampleTool) { %>
|
|
55
|
+
### example_tool
|
|
56
|
+
|
|
57
|
+
A sample tool that demonstrates basic MCP tool functionality.
|
|
58
|
+
|
|
59
|
+
**Parameters:**
|
|
60
|
+
- `query` (string, required): The query parameter
|
|
61
|
+
|
|
62
|
+
<% } %>
|
|
63
|
+
<% tools.forEach(function(tool) { %>
|
|
64
|
+
### <%= tool.name %>
|
|
65
|
+
|
|
66
|
+
<%= tool.description %>
|
|
67
|
+
|
|
68
|
+
<% if (tool.parameters && tool.parameters.length > 0) { %>
|
|
69
|
+
**Parameters:**
|
|
70
|
+
<% tool.parameters.forEach(function(param) { %>
|
|
71
|
+
- `<%= param.name %>` (<%= param.type %><%= param.required ? ', required' : '' %>): <%= param.description %>
|
|
72
|
+
<% }); %>
|
|
73
|
+
<% } %>
|
|
74
|
+
<% }); %>
|
|
75
|
+
|
|
76
|
+
## License
|
|
77
|
+
|
|
78
|
+
MIT
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "<%= name %>"
|
|
7
|
+
version = "1.0.0"
|
|
8
|
+
description = "<%= description || 'MCP Server generated by create-mcp-server' %>"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
requires-python = ">=3.10"
|
|
12
|
+
dependencies = [
|
|
13
|
+
"mcp>=1.0.0",
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
[project.scripts]
|
|
17
|
+
<%= name %> = "src.server:main"
|
|
18
|
+
|
|
19
|
+
[tool.hatch.build.targets.wheel]
|
|
20
|
+
packages = ["src"]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
mcp>=1.0.0
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"""
|
|
2
|
+
<%= name %> MCP Server
|
|
3
|
+
<%= description || 'Generated by create-mcp-server' %>
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import asyncio
|
|
7
|
+
from mcp.server import Server
|
|
8
|
+
<% if (transport === 'stdio') { %>
|
|
9
|
+
from mcp.server.stdio import stdio_server
|
|
10
|
+
<% } else { %>
|
|
11
|
+
from mcp.server.sse import SseServerTransport
|
|
12
|
+
<% } %>
|
|
13
|
+
from mcp.types import Tool, TextContent
|
|
14
|
+
|
|
15
|
+
# Create the server instance
|
|
16
|
+
server = Server("<%= name %>")
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@server.list_tools()
|
|
20
|
+
async def list_tools() -> list[Tool]:
|
|
21
|
+
"""List available tools."""
|
|
22
|
+
return [
|
|
23
|
+
<% if (includeExampleTool) { %>
|
|
24
|
+
Tool(
|
|
25
|
+
name="example_tool",
|
|
26
|
+
description="An example tool that echoes the input",
|
|
27
|
+
inputSchema={
|
|
28
|
+
"type": "object",
|
|
29
|
+
"properties": {
|
|
30
|
+
"query": {
|
|
31
|
+
"type": "string",
|
|
32
|
+
"description": "The query to echo",
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
"required": ["query"],
|
|
36
|
+
},
|
|
37
|
+
),
|
|
38
|
+
<% } %>
|
|
39
|
+
<% tools.forEach(function(tool) { %>
|
|
40
|
+
Tool(
|
|
41
|
+
name="<%= tool.name %>",
|
|
42
|
+
description="<%= tool.description %>",
|
|
43
|
+
inputSchema={
|
|
44
|
+
"type": "object",
|
|
45
|
+
"properties": {
|
|
46
|
+
<% tool.parameters.forEach(function(param, index) { %>
|
|
47
|
+
"<%= param.name %>": {
|
|
48
|
+
"type": "<%= param.type %>",
|
|
49
|
+
"description": "<%= param.description %>",
|
|
50
|
+
}<%= index < tool.parameters.length - 1 ? ',' : '' %>
|
|
51
|
+
<% }); %>
|
|
52
|
+
},
|
|
53
|
+
"required": [<%= tool.parameters.filter(p => p.required).map(p => '"' + p.name + '"').join(', ') %>],
|
|
54
|
+
},
|
|
55
|
+
),
|
|
56
|
+
<% }); %>
|
|
57
|
+
]
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
@server.call_tool()
|
|
61
|
+
async def call_tool(name: str, arguments: dict) -> list[TextContent]:
|
|
62
|
+
"""Handle tool calls."""
|
|
63
|
+
<% if (includeExampleTool) { %>
|
|
64
|
+
if name == "example_tool":
|
|
65
|
+
query = arguments.get("query", "")
|
|
66
|
+
return [TextContent(type="text", text=f"Echo: {query}")]
|
|
67
|
+
<% } %>
|
|
68
|
+
|
|
69
|
+
<% tools.forEach(function(tool) { %>
|
|
70
|
+
if name == "<%= tool.name %>":
|
|
71
|
+
# TODO: Implement <%= tool.name %> logic
|
|
72
|
+
<% tool.parameters.forEach(function(param) { %>
|
|
73
|
+
<%= param.name %> = arguments.get("<%= param.name %>")
|
|
74
|
+
<% }); %>
|
|
75
|
+
return [TextContent(type="text", text=f"<%= tool.name %> called with: {arguments}")]
|
|
76
|
+
<% }); %>
|
|
77
|
+
|
|
78
|
+
raise ValueError(f"Unknown tool: {name}")
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
async def main():
|
|
82
|
+
"""Main entry point."""
|
|
83
|
+
<% if (transport === 'stdio') { %>
|
|
84
|
+
async with stdio_server() as (read_stream, write_stream):
|
|
85
|
+
await server.run(
|
|
86
|
+
read_stream,
|
|
87
|
+
write_stream,
|
|
88
|
+
server.create_initialization_options(),
|
|
89
|
+
)
|
|
90
|
+
<% } else { %>
|
|
91
|
+
# SSE transport implementation
|
|
92
|
+
transport = SseServerTransport("/messages")
|
|
93
|
+
await server.run(transport)
|
|
94
|
+
<% } %>
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
if __name__ == "__main__":
|
|
98
|
+
asyncio.run(main())
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Tools package for <%= name %>"""
|