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/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,8 @@
1
+ # Environment variables for your MCP server
2
+ # Copy this file to .env and fill in your values
3
+
4
+ # Example API key
5
+ # API_KEY=your-api-key-here
6
+
7
+ # Server configuration
8
+ # PORT=3000
@@ -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,3 @@
1
+ """<%= name %> - MCP Server"""
2
+
3
+ __version__ = "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 %>"""