@mr-aftab-ahmad-khan/create-mcp-server 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.cjs ADDED
@@ -0,0 +1,760 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var src_exports = {};
22
+ __export(src_exports, {
23
+ TEMPLATES: () => TEMPLATES,
24
+ scaffold: () => scaffold
25
+ });
26
+ module.exports = __toCommonJS(src_exports);
27
+
28
+ // src/scaffold.ts
29
+ var import_node_fs = require("fs");
30
+ var import_node_path = require("path");
31
+
32
+ // src/templates/common.ts
33
+ var TS_TSCONFIG = {
34
+ path: "tsconfig.json",
35
+ contents: JSON.stringify(
36
+ {
37
+ compilerOptions: {
38
+ target: "ES2022",
39
+ module: "ESNext",
40
+ moduleResolution: "Bundler",
41
+ strict: true,
42
+ esModuleInterop: true,
43
+ skipLibCheck: true,
44
+ declaration: false,
45
+ outDir: "dist"
46
+ },
47
+ include: ["src/**/*"]
48
+ },
49
+ null,
50
+ 2
51
+ ) + "\n"
52
+ };
53
+ function packageJson(opts, deps = {}) {
54
+ const isTs = opts.language === "typescript";
55
+ return {
56
+ path: "package.json",
57
+ contents: JSON.stringify(
58
+ {
59
+ name: opts.name,
60
+ version: "0.1.0",
61
+ private: true,
62
+ type: "module",
63
+ main: isTs ? "dist/index.js" : "src/index.js",
64
+ scripts: {
65
+ start: isTs ? "node dist/index.js" : "node src/index.js",
66
+ ...isTs ? { build: "tsc", dev: "tsx watch src/index.ts" } : {}
67
+ },
68
+ dependencies: {
69
+ "@modelcontextprotocol/sdk": "^1.0.0",
70
+ zod: "^3.22.4",
71
+ ...deps
72
+ },
73
+ ...isTs ? {
74
+ devDependencies: {
75
+ "@types/node": "^20.11.0",
76
+ tsx: "^4.7.0",
77
+ typescript: "^5.4.0"
78
+ }
79
+ } : {}
80
+ },
81
+ null,
82
+ 2
83
+ ) + "\n"
84
+ };
85
+ }
86
+ function gitignore() {
87
+ return {
88
+ path: ".gitignore",
89
+ contents: ["node_modules", "dist", ".env", "*.log", ".DS_Store", ""].join("\n")
90
+ };
91
+ }
92
+ function envExample(vars) {
93
+ const lines = [
94
+ "# Environment variables for this MCP server",
95
+ ...vars.map((v) => `${v.name}= # ${v.description}`),
96
+ ""
97
+ ];
98
+ return { path: ".env.example", contents: lines.join("\n") };
99
+ }
100
+ function authMiddleware(opts) {
101
+ if (!opts.auth) return "";
102
+ return `
103
+ function requireAuth(extra: { request?: { headers?: Record<string, string> } }): void {
104
+ const expected = process.env.MCP_API_KEY;
105
+ if (!expected) return;
106
+ const provided = extra.request?.headers?.["x-api-key"];
107
+ if (provided !== expected) throw new Error("Unauthorized");
108
+ }
109
+ `.trim();
110
+ }
111
+ function readme(opts, extra) {
112
+ const bin = opts.language === "typescript" ? "node dist/index.js" : "node src/index.js";
113
+ const cmd = opts.transport === "stdio" ? bin : `${bin} --port 8080`;
114
+ return {
115
+ path: "README.md",
116
+ contents: `# ${opts.name}
117
+
118
+ An MCP server scaffolded by \`create-mcp-server\`.
119
+
120
+ ## Run
121
+
122
+ \`\`\`bash
123
+ cp .env.example .env
124
+ # fill in values
125
+ npm install
126
+ ${opts.language === "typescript" ? "npm run build\n" : ""}npm start
127
+ \`\`\`
128
+
129
+ ## Claude Desktop config
130
+
131
+ \`\`\`json
132
+ {
133
+ "mcpServers": {
134
+ "${opts.name}": {
135
+ "command": "${bin.split(" ")[0]}",
136
+ "args": ${JSON.stringify(bin.split(" ").slice(1))},
137
+ "env": {}
138
+ }
139
+ }
140
+ }
141
+ \`\`\`
142
+
143
+ ${extra}
144
+
145
+ > Generated by \`create-mcp-server\`. Replace this README with your own.
146
+ `
147
+ };
148
+ }
149
+
150
+ // src/templates/blank.ts
151
+ var blankIndexTs = (auth) => `
152
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
153
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
154
+ import {
155
+ CallToolRequestSchema,
156
+ ListToolsRequestSchema,
157
+ type Tool,
158
+ } from "@modelcontextprotocol/sdk/types.js";
159
+ import { z } from "zod";
160
+
161
+ ${auth ? authMiddleware({ auth: true, name: "", template: "blank", transport: "stdio", language: "typescript" }) : ""}
162
+
163
+ const server = new Server(
164
+ { name: "blank-mcp-server", version: "0.1.0" },
165
+ { capabilities: { tools: {} } },
166
+ );
167
+
168
+ const TOOLS: Tool[] = [
169
+ {
170
+ name: "echo",
171
+ description: "Returns whatever message you send. The simplest possible tool.",
172
+ inputSchema: {
173
+ type: "object",
174
+ properties: { message: { type: "string" } },
175
+ required: ["message"],
176
+ },
177
+ },
178
+ ];
179
+
180
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOLS }));
181
+
182
+ server.setRequestHandler(CallToolRequestSchema, async (request${auth ? ", extra" : ""}) => {
183
+ ${auth ? "requireAuth(extra as any);" : ""}
184
+ if (request.params.name === "echo") {
185
+ const args = z.object({ message: z.string() }).parse(request.params.arguments);
186
+ return { content: [{ type: "text", text: args.message }] };
187
+ }
188
+ return { content: [{ type: "text", text: "Unknown tool: " + request.params.name }], isError: true };
189
+ });
190
+
191
+ const transport = new StdioServerTransport();
192
+ await server.connect(transport);
193
+ console.error("blank-mcp-server: ready");
194
+ `.trim() + "\n";
195
+ var blankTemplate = {
196
+ name: "blank",
197
+ description: "Minimal MCP server with one example tool and explanatory comments.",
198
+ envVars: [],
199
+ files(opts) {
200
+ const files = [packageJson(opts), gitignore(), envExample([])];
201
+ if (opts.language === "typescript") {
202
+ files.push(TS_TSCONFIG);
203
+ files.push({ path: "src/index.ts", contents: blankIndexTs(opts.auth) });
204
+ } else {
205
+ files.push({
206
+ path: "src/index.js",
207
+ contents: blankIndexTs(opts.auth).replace(/: \w+(\[\])?/g, "").replace(/import type[\s\S]+?from[^;]+;\n/g, "")
208
+ });
209
+ }
210
+ files.push(
211
+ readme(opts, `
212
+ ## Tools
213
+
214
+ - \`echo\` \u2014 echoes back the supplied \`message\`.
215
+
216
+ ## Adding more tools
217
+
218
+ 1. Append to the \`TOOLS\` array with a JSON Schema for inputs.
219
+ 2. Add a branch to the \`CallToolRequestSchema\` handler returning \`{ content: [...] }\`.
220
+ `)
221
+ );
222
+ return files;
223
+ }
224
+ };
225
+
226
+ // src/templates/postgres.ts
227
+ var postgresIndex = (auth) => `
228
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
229
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
230
+ import {
231
+ CallToolRequestSchema,
232
+ ListToolsRequestSchema,
233
+ type Tool,
234
+ } from "@modelcontextprotocol/sdk/types.js";
235
+ import { z } from "zod";
236
+ import pg from "pg";
237
+
238
+ const { Pool } = pg;
239
+ const pool = new Pool({ connectionString: process.env.DATABASE_URL });
240
+
241
+ ${auth ? authMiddleware({ auth: true, name: "", template: "postgres", transport: "stdio", language: "typescript" }) : ""}
242
+
243
+ const server = new Server(
244
+ { name: "postgres-mcp", version: "0.1.0" },
245
+ { capabilities: { tools: {} } },
246
+ );
247
+
248
+ const TOOLS: Tool[] = [
249
+ {
250
+ name: "query",
251
+ description: "Run a read-only SQL query with bound parameters",
252
+ inputSchema: {
253
+ type: "object",
254
+ properties: { sql: { type: "string" }, params: { type: "array", items: {} } },
255
+ required: ["sql"],
256
+ },
257
+ },
258
+ {
259
+ name: "list_tables",
260
+ description: "List all tables in the public schema",
261
+ inputSchema: { type: "object", properties: {} },
262
+ },
263
+ {
264
+ name: "describe_table",
265
+ description: "Describe columns and types of a given table",
266
+ inputSchema: {
267
+ type: "object",
268
+ properties: { table: { type: "string" } },
269
+ required: ["table"],
270
+ },
271
+ },
272
+ {
273
+ name: "insert",
274
+ description: "Insert a row into the named table",
275
+ inputSchema: {
276
+ type: "object",
277
+ properties: { table: { type: "string" }, row: { type: "object" } },
278
+ required: ["table", "row"],
279
+ },
280
+ },
281
+ {
282
+ name: "update",
283
+ description: "Update rows in the named table matching a where clause (parameterised)",
284
+ inputSchema: {
285
+ type: "object",
286
+ properties: {
287
+ table: { type: "string" },
288
+ set: { type: "object" },
289
+ where: { type: "object" },
290
+ },
291
+ required: ["table", "set", "where"],
292
+ },
293
+ },
294
+ ];
295
+
296
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOLS }));
297
+
298
+ server.setRequestHandler(CallToolRequestSchema, async (request${auth ? ", extra" : ""}) => {
299
+ ${auth ? "requireAuth(extra as any);" : ""}
300
+ try {
301
+ if (request.params.name === "query") {
302
+ const args = z.object({ sql: z.string(), params: z.array(z.unknown()).optional() }).parse(request.params.arguments);
303
+ const res = await pool.query(args.sql, args.params as unknown[] | undefined);
304
+ return { content: [{ type: "text", text: JSON.stringify({ rowCount: res.rowCount, rows: res.rows }, null, 2) }] };
305
+ }
306
+ if (request.params.name === "list_tables") {
307
+ const res = await pool.query("SELECT tablename FROM pg_catalog.pg_tables WHERE schemaname = 'public'");
308
+ return { content: [{ type: "text", text: JSON.stringify(res.rows, null, 2) }] };
309
+ }
310
+ if (request.params.name === "describe_table") {
311
+ const args = z.object({ table: z.string() }).parse(request.params.arguments);
312
+ const res = await pool.query(
313
+ "SELECT column_name, data_type, is_nullable FROM information_schema.columns WHERE table_schema='public' AND table_name=$1 ORDER BY ordinal_position",
314
+ [args.table],
315
+ );
316
+ return { content: [{ type: "text", text: JSON.stringify(res.rows, null, 2) }] };
317
+ }
318
+ if (request.params.name === "insert") {
319
+ const args = z.object({ table: z.string(), row: z.record(z.unknown()) }).parse(request.params.arguments);
320
+ const cols = Object.keys(args.row);
321
+ const placeholders = cols.map((_, i) => "$" + (i + 1)).join(", ");
322
+ const sql = "INSERT INTO " + JSON.stringify(args.table).slice(1, -1) + " (" + cols.map((c) => '"' + c + '"').join(", ") + ") VALUES (" + placeholders + ") RETURNING *";
323
+ const res = await pool.query(sql, cols.map((c) => args.row[c]));
324
+ return { content: [{ type: "text", text: JSON.stringify(res.rows[0], null, 2) }] };
325
+ }
326
+ if (request.params.name === "update") {
327
+ const args = z.object({ table: z.string(), set: z.record(z.unknown()), where: z.record(z.unknown()) }).parse(request.params.arguments);
328
+ const setKeys = Object.keys(args.set);
329
+ const whereKeys = Object.keys(args.where);
330
+ const setSql = setKeys.map((k, i) => '"' + k + '" = $' + (i + 1)).join(", ");
331
+ const whereSql = whereKeys.map((k, i) => '"' + k + '" = $' + (i + 1 + setKeys.length)).join(" AND ");
332
+ const sql = "UPDATE " + JSON.stringify(args.table).slice(1, -1) + " SET " + setSql + " WHERE " + whereSql + " RETURNING *";
333
+ const params = [...setKeys.map((k) => args.set[k]), ...whereKeys.map((k) => args.where[k])];
334
+ const res = await pool.query(sql, params);
335
+ return { content: [{ type: "text", text: JSON.stringify({ updated: res.rowCount, rows: res.rows }, null, 2) }] };
336
+ }
337
+ return { content: [{ type: "text", text: "Unknown tool" }], isError: true };
338
+ } catch (err) {
339
+ return { content: [{ type: "text", text: String(err) }], isError: true };
340
+ }
341
+ });
342
+
343
+ const transport = new StdioServerTransport();
344
+ await server.connect(transport);
345
+ console.error("postgres-mcp: connected");
346
+ `.trim() + "\n";
347
+ var postgresTemplate = {
348
+ name: "postgres",
349
+ description: "MCP server backed by Postgres with query, list_tables, describe_table, insert, update tools.",
350
+ envVars: [
351
+ { name: "DATABASE_URL", description: "Postgres connection string e.g. postgres://user:pass@host:5432/db" }
352
+ ],
353
+ files(opts) {
354
+ const files = [
355
+ packageJson(opts, { pg: "^8.11.3" }),
356
+ gitignore(),
357
+ envExample(this.envVars)
358
+ ];
359
+ if (opts.language === "typescript") {
360
+ files.push(TS_TSCONFIG);
361
+ files.push({ path: "src/index.ts", contents: postgresIndex(opts.auth) });
362
+ } else {
363
+ files.push({
364
+ path: "src/index.js",
365
+ contents: postgresIndex(opts.auth).replace(/: \w+(\[\])?/g, "").replace(/import type[\s\S]+?from[^;]+;\n/g, "")
366
+ });
367
+ }
368
+ files.push(
369
+ readme(opts, `
370
+ ## Tools
371
+
372
+ - \`query\` \u2014 run an arbitrary SQL query with bound parameters
373
+ - \`list_tables\` \u2014 list public-schema tables
374
+ - \`describe_table\` \u2014 describe columns of a table
375
+ - \`insert\` \u2014 insert a row into a table
376
+ - \`update\` \u2014 update rows matching a where clause
377
+ `)
378
+ );
379
+ return files;
380
+ }
381
+ };
382
+
383
+ // src/templates/stripe.ts
384
+ var stripeIndex = (auth) => `
385
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
386
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
387
+ import {
388
+ CallToolRequestSchema,
389
+ ListToolsRequestSchema,
390
+ type Tool,
391
+ } from "@modelcontextprotocol/sdk/types.js";
392
+ import Stripe from "stripe";
393
+ import { z } from "zod";
394
+
395
+ const stripe = new Stripe(process.env.STRIPE_SECRET_KEY ?? "");
396
+
397
+ ${auth ? authMiddleware({ auth: true, name: "", template: "stripe", transport: "stdio", language: "typescript" }) : ""}
398
+
399
+ const server = new Server({ name: "stripe-mcp", version: "0.1.0" }, { capabilities: { tools: {} } });
400
+
401
+ const TOOLS: Tool[] = [
402
+ { name: "list_customers", description: "List Stripe customers", inputSchema: { type: "object", properties: { limit: { type: "number" } } } },
403
+ { name: "get_customer", description: "Get a customer by id", inputSchema: { type: "object", properties: { id: { type: "string" } }, required: ["id"] } },
404
+ { name: "list_invoices", description: "List recent invoices", inputSchema: { type: "object", properties: { limit: { type: "number" } } } },
405
+ {
406
+ name: "create_payment_link",
407
+ description: "Create a Stripe payment link for a price",
408
+ inputSchema: { type: "object", properties: { price: { type: "string" }, quantity: { type: "number" } }, required: ["price"] },
409
+ },
410
+ { name: "get_balance", description: "Get the current Stripe balance", inputSchema: { type: "object", properties: {} } },
411
+ ];
412
+
413
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOLS }));
414
+
415
+ server.setRequestHandler(CallToolRequestSchema, async (request${auth ? ", extra" : ""}) => {
416
+ ${auth ? "requireAuth(extra as any);" : ""}
417
+ try {
418
+ if (request.params.name === "list_customers") {
419
+ const args = z.object({ limit: z.number().optional() }).parse(request.params.arguments ?? {});
420
+ const res = await stripe.customers.list({ limit: args.limit ?? 10 });
421
+ return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
422
+ }
423
+ if (request.params.name === "get_customer") {
424
+ const args = z.object({ id: z.string() }).parse(request.params.arguments);
425
+ const c = await stripe.customers.retrieve(args.id);
426
+ return { content: [{ type: "text", text: JSON.stringify(c, null, 2) }] };
427
+ }
428
+ if (request.params.name === "list_invoices") {
429
+ const args = z.object({ limit: z.number().optional() }).parse(request.params.arguments ?? {});
430
+ const res = await stripe.invoices.list({ limit: args.limit ?? 10 });
431
+ return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
432
+ }
433
+ if (request.params.name === "create_payment_link") {
434
+ const args = z.object({ price: z.string(), quantity: z.number().default(1) }).parse(request.params.arguments);
435
+ const link = await stripe.paymentLinks.create({ line_items: [{ price: args.price, quantity: args.quantity }] });
436
+ return { content: [{ type: "text", text: JSON.stringify(link, null, 2) }] };
437
+ }
438
+ if (request.params.name === "get_balance") {
439
+ const b = await stripe.balance.retrieve();
440
+ return { content: [{ type: "text", text: JSON.stringify(b, null, 2) }] };
441
+ }
442
+ return { content: [{ type: "text", text: "Unknown tool" }], isError: true };
443
+ } catch (err) {
444
+ return { content: [{ type: "text", text: String(err) }], isError: true };
445
+ }
446
+ });
447
+
448
+ const transport = new StdioServerTransport();
449
+ await server.connect(transport);
450
+ console.error("stripe-mcp: connected");
451
+ `.trim() + "\n";
452
+ var stripeTemplate = {
453
+ name: "stripe",
454
+ description: "Stripe customer / invoice / payment link tools via the official Stripe SDK.",
455
+ envVars: [{ name: "STRIPE_SECRET_KEY", description: "Stripe secret key (sk_test_... or sk_live_...)" }],
456
+ files(opts) {
457
+ const files = [
458
+ packageJson(opts, { stripe: "^14.20.0" }),
459
+ gitignore(),
460
+ envExample(this.envVars)
461
+ ];
462
+ if (opts.language === "typescript") {
463
+ files.push(TS_TSCONFIG);
464
+ files.push({ path: "src/index.ts", contents: stripeIndex(opts.auth) });
465
+ } else {
466
+ files.push({
467
+ path: "src/index.js",
468
+ contents: stripeIndex(opts.auth).replace(/: \w+(\[\])?/g, "").replace(/import type[\s\S]+?from[^;]+;\n/g, "")
469
+ });
470
+ }
471
+ files.push(
472
+ readme(opts, `
473
+ ## Tools
474
+
475
+ - \`list_customers\`, \`get_customer\` \u2014 customer reads
476
+ - \`list_invoices\` \u2014 invoice reads
477
+ - \`create_payment_link\` \u2014 create a Stripe payment link
478
+ - \`get_balance\` \u2014 current balance
479
+ `)
480
+ );
481
+ return files;
482
+ }
483
+ };
484
+
485
+ // src/templates/filesystem.ts
486
+ var fsIndex = (auth) => `
487
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
488
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
489
+ import {
490
+ CallToolRequestSchema,
491
+ ListToolsRequestSchema,
492
+ type Tool,
493
+ } from "@modelcontextprotocol/sdk/types.js";
494
+ import { z } from "zod";
495
+ import { readFile, writeFile, readdir, stat } from "node:fs/promises";
496
+ import { join, resolve, sep } from "node:path";
497
+
498
+ const ROOT = resolve(process.env.SANDBOX_ROOT ?? process.cwd());
499
+
500
+ function safePath(p: string): string {
501
+ const abs = resolve(ROOT, p);
502
+ if (!abs.startsWith(ROOT + sep) && abs !== ROOT) throw new Error("Path escapes sandbox");
503
+ return abs;
504
+ }
505
+
506
+ ${auth ? authMiddleware({ auth: true, name: "", template: "filesystem", transport: "stdio", language: "typescript" }) : ""}
507
+
508
+ const server = new Server({ name: "filesystem-mcp", version: "0.1.0" }, { capabilities: { tools: {} } });
509
+
510
+ const TOOLS: Tool[] = [
511
+ { name: "read_file", description: "Read a UTF-8 file", inputSchema: { type: "object", properties: { path: { type: "string" } }, required: ["path"] } },
512
+ { name: "write_file", description: "Write a UTF-8 file", inputSchema: { type: "object", properties: { path: { type: "string" }, contents: { type: "string" } }, required: ["path", "contents"] } },
513
+ { name: "list_directory", description: "List a directory", inputSchema: { type: "object", properties: { path: { type: "string" } }, required: ["path"] } },
514
+ { name: "search_files", description: "Recursively grep files for a substring", inputSchema: { type: "object", properties: { needle: { type: "string" }, path: { type: "string" } }, required: ["needle"] } },
515
+ { name: "get_file_info", description: "stat a file or directory", inputSchema: { type: "object", properties: { path: { type: "string" } }, required: ["path"] } },
516
+ ];
517
+
518
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOLS }));
519
+
520
+ server.setRequestHandler(CallToolRequestSchema, async (request${auth ? ", extra" : ""}) => {
521
+ ${auth ? "requireAuth(extra as any);" : ""}
522
+ try {
523
+ if (request.params.name === "read_file") {
524
+ const args = z.object({ path: z.string() }).parse(request.params.arguments);
525
+ const content = await readFile(safePath(args.path), "utf8");
526
+ return { content: [{ type: "text", text: content }] };
527
+ }
528
+ if (request.params.name === "write_file") {
529
+ const args = z.object({ path: z.string(), contents: z.string() }).parse(request.params.arguments);
530
+ await writeFile(safePath(args.path), args.contents, "utf8");
531
+ return { content: [{ type: "text", text: "OK" }] };
532
+ }
533
+ if (request.params.name === "list_directory") {
534
+ const args = z.object({ path: z.string() }).parse(request.params.arguments);
535
+ const entries = await readdir(safePath(args.path), { withFileTypes: true });
536
+ return { content: [{ type: "text", text: JSON.stringify(entries.map((e) => ({ name: e.name, dir: e.isDirectory() })), null, 2) }] };
537
+ }
538
+ if (request.params.name === "search_files") {
539
+ const args = z.object({ needle: z.string(), path: z.string().default(".") }).parse(request.params.arguments);
540
+ const hits = await search(safePath(args.path), args.needle);
541
+ return { content: [{ type: "text", text: JSON.stringify(hits, null, 2) }] };
542
+ }
543
+ if (request.params.name === "get_file_info") {
544
+ const args = z.object({ path: z.string() }).parse(request.params.arguments);
545
+ const s = await stat(safePath(args.path));
546
+ return { content: [{ type: "text", text: JSON.stringify({ size: s.size, isDir: s.isDirectory(), mtime: s.mtime }, null, 2) }] };
547
+ }
548
+ return { content: [{ type: "text", text: "Unknown tool" }], isError: true };
549
+ } catch (err) {
550
+ return { content: [{ type: "text", text: String(err) }], isError: true };
551
+ }
552
+ });
553
+
554
+ async function search(root: string, needle: string): Promise<{ file: string; line: number; text: string }[]> {
555
+ const out: { file: string; line: number; text: string }[] = [];
556
+ async function walk(d: string): Promise<void> {
557
+ const entries = await readdir(d, { withFileTypes: true });
558
+ for (const e of entries) {
559
+ const p = join(d, e.name);
560
+ if (e.isDirectory()) await walk(p);
561
+ else if (e.isFile()) {
562
+ try {
563
+ const txt = await readFile(p, "utf8");
564
+ const lines = txt.split(/\\r?\\n/);
565
+ for (let i = 0; i < lines.length; i++) {
566
+ const line = lines[i] ?? "";
567
+ if (line.includes(needle)) out.push({ file: p, line: i + 1, text: line });
568
+ }
569
+ } catch {
570
+ // skip binary or unreadable files
571
+ }
572
+ }
573
+ }
574
+ }
575
+ await walk(root);
576
+ return out;
577
+ }
578
+
579
+ const transport = new StdioServerTransport();
580
+ await server.connect(transport);
581
+ console.error("filesystem-mcp: ready under " + ROOT);
582
+ `.trim() + "\n";
583
+ var filesystemTemplate = {
584
+ name: "filesystem",
585
+ description: "Sandboxed filesystem tools (read, write, list, search, stat).",
586
+ envVars: [{ name: "SANDBOX_ROOT", description: "Absolute path the server is allowed to read/write" }],
587
+ files(opts) {
588
+ const files = [packageJson(opts), gitignore(), envExample(this.envVars)];
589
+ if (opts.language === "typescript") {
590
+ files.push(TS_TSCONFIG);
591
+ files.push({ path: "src/index.ts", contents: fsIndex(opts.auth) });
592
+ } else {
593
+ files.push({
594
+ path: "src/index.js",
595
+ contents: fsIndex(opts.auth).replace(/: \w+(\[\])?/g, "").replace(/import type[\s\S]+?from[^;]+;\n/g, "")
596
+ });
597
+ }
598
+ files.push(readme(opts, "## Tools\n\n- read_file, write_file, list_directory, search_files, get_file_info"));
599
+ return files;
600
+ }
601
+ };
602
+
603
+ // src/templates/rest.ts
604
+ var restIndex = (auth) => `
605
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
606
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
607
+ import {
608
+ CallToolRequestSchema,
609
+ ListToolsRequestSchema,
610
+ type Tool,
611
+ } from "@modelcontextprotocol/sdk/types.js";
612
+ import { z } from "zod";
613
+ import { readFile } from "node:fs/promises";
614
+
615
+ ${auth ? authMiddleware({ auth: true, name: "", template: "rest", transport: "stdio", language: "typescript" }) : ""}
616
+
617
+ interface OpenApiSpec {
618
+ servers?: Array<{ url: string }>;
619
+ paths: Record<string, Record<string, { operationId?: string; summary?: string; parameters?: Array<{ name: string; in: string; required?: boolean; schema?: { type?: string } }>; requestBody?: { content?: { "application/json"?: { schema?: { type: string; properties?: Record<string, unknown> } } } } }>>;
620
+ }
621
+
622
+ const specPath = process.env.OPENAPI_SPEC_PATH ?? "openapi.json";
623
+ const spec = JSON.parse(await readFile(specPath, "utf8")) as OpenApiSpec;
624
+ const baseUrl = spec.servers?.[0]?.url ?? process.env.API_BASE_URL ?? "";
625
+
626
+ interface ToolEntry { method: string; path: string; spec: NonNullable<OpenApiSpec["paths"]>[string][string]; }
627
+ const toolMap = new Map<string, ToolEntry>();
628
+
629
+ const TOOLS: Tool[] = [];
630
+ for (const [route, methods] of Object.entries(spec.paths)) {
631
+ for (const [method, op] of Object.entries(methods)) {
632
+ if (!["get", "post"].includes(method)) continue;
633
+ const name = op.operationId ?? (method + "_" + route).replace(/[^a-zA-Z0-9_]/g, "_");
634
+ const props: Record<string, unknown> = {};
635
+ const required: string[] = [];
636
+ for (const p of op.parameters ?? []) {
637
+ props[p.name] = { type: p.schema?.type ?? "string" };
638
+ if (p.required) required.push(p.name);
639
+ }
640
+ const bodySchema = op.requestBody?.content?.["application/json"]?.schema;
641
+ if (bodySchema?.properties) {
642
+ for (const [k, v] of Object.entries(bodySchema.properties)) {
643
+ props[k] = v;
644
+ }
645
+ }
646
+ TOOLS.push({
647
+ name,
648
+ description: op.summary ?? (method.toUpperCase() + " " + route),
649
+ inputSchema: { type: "object", properties: props, required },
650
+ });
651
+ toolMap.set(name, { method, path: route, spec: op });
652
+ }
653
+ }
654
+
655
+ const server = new Server({ name: "rest-mcp", version: "0.1.0" }, { capabilities: { tools: {} } });
656
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOLS }));
657
+ server.setRequestHandler(CallToolRequestSchema, async (request${auth ? ", extra" : ""}) => {
658
+ ${auth ? "requireAuth(extra as any);" : ""}
659
+ const entry = toolMap.get(request.params.name);
660
+ if (!entry) return { content: [{ type: "text", text: "Unknown tool" }], isError: true };
661
+ const args = z.record(z.unknown()).parse(request.params.arguments ?? {});
662
+
663
+ let url = baseUrl + entry.path;
664
+ for (const p of entry.spec.parameters ?? []) {
665
+ if (p.in === "path") url = url.replace("{" + p.name + "}", encodeURIComponent(String(args[p.name] ?? "")));
666
+ }
667
+ const query: string[] = [];
668
+ for (const p of entry.spec.parameters ?? []) {
669
+ if (p.in === "query" && args[p.name] !== undefined) {
670
+ query.push(encodeURIComponent(p.name) + "=" + encodeURIComponent(String(args[p.name])));
671
+ }
672
+ }
673
+ if (query.length) url += "?" + query.join("&");
674
+
675
+ const headers: Record<string, string> = { "content-type": "application/json" };
676
+ if (process.env.API_BEARER_TOKEN) headers.authorization = "Bearer " + process.env.API_BEARER_TOKEN;
677
+ if (process.env.API_KEY_HEADER && process.env.API_KEY) headers[process.env.API_KEY_HEADER] = process.env.API_KEY;
678
+
679
+ const init: RequestInit = { method: entry.method.toUpperCase(), headers };
680
+ if (entry.method !== "get") {
681
+ const bodyKeys = Object.keys(entry.spec.requestBody?.content?.["application/json"]?.schema?.properties ?? {});
682
+ const body: Record<string, unknown> = {};
683
+ for (const k of bodyKeys) if (args[k] !== undefined) body[k] = args[k];
684
+ init.body = JSON.stringify(body);
685
+ }
686
+ const res = await fetch(url, init);
687
+ const text = await res.text();
688
+ return { content: [{ type: "text", text }], isError: !res.ok };
689
+ });
690
+
691
+ const transport = new StdioServerTransport();
692
+ await server.connect(transport);
693
+ console.error("rest-mcp: ready (" + TOOLS.length + " tools)");
694
+ `.trim() + "\n";
695
+ var restTemplate = {
696
+ name: "rest",
697
+ description: "Wraps any OpenAPI 3.0 REST API as MCP tools.",
698
+ envVars: [
699
+ { name: "OPENAPI_SPEC_PATH", description: "Path to an OpenAPI 3.0 JSON file" },
700
+ { name: "API_BASE_URL", description: "Override servers[0].url from the spec" },
701
+ { name: "API_BEARER_TOKEN", description: "Optional Bearer token" },
702
+ { name: "API_KEY_HEADER", description: "Optional API-key header name" },
703
+ { name: "API_KEY", description: "Optional API-key value" }
704
+ ],
705
+ files(opts) {
706
+ const files = [packageJson(opts), gitignore(), envExample(this.envVars)];
707
+ if (opts.language === "typescript") {
708
+ files.push(TS_TSCONFIG);
709
+ files.push({ path: "src/index.ts", contents: restIndex(opts.auth) });
710
+ } else {
711
+ files.push({
712
+ path: "src/index.js",
713
+ contents: restIndex(opts.auth).replace(/: \w+(\[\])?/g, "").replace(/import type[\s\S]+?from[^;]+;\n/g, "")
714
+ });
715
+ }
716
+ files.push({
717
+ path: "openapi.json",
718
+ contents: JSON.stringify({
719
+ openapi: "3.0.0",
720
+ info: { title: "Example", version: "1.0.0" },
721
+ servers: [{ url: "https://api.example.com" }],
722
+ paths: {
723
+ "/ping": { get: { operationId: "ping", summary: "Health check" } }
724
+ }
725
+ }, null, 2) + "\n"
726
+ });
727
+ files.push(readme(opts, "## Tools\n\nAuto-generated from `openapi.json`. Replace the spec to expose your own API."));
728
+ return files;
729
+ }
730
+ };
731
+
732
+ // src/scaffold.ts
733
+ var TEMPLATES = {
734
+ blank: blankTemplate,
735
+ postgres: postgresTemplate,
736
+ stripe: stripeTemplate,
737
+ filesystem: filesystemTemplate,
738
+ rest: restTemplate
739
+ };
740
+ function scaffold(opts) {
741
+ const tpl = TEMPLATES[opts.template];
742
+ if (!tpl) throw new Error(`Unknown template: ${opts.template}`);
743
+ const target = (0, import_node_path.resolve)(opts.target ?? opts.name);
744
+ if ((0, import_node_fs.existsSync)(target) && (0, import_node_fs.readdirSync)(target).length > 0) {
745
+ throw new Error(`Target directory is not empty: ${target}`);
746
+ }
747
+ (0, import_node_fs.mkdirSync)(target, { recursive: true });
748
+ for (const file of tpl.files(opts)) {
749
+ const out = (0, import_node_path.join)(target, file.path);
750
+ (0, import_node_fs.mkdirSync)((0, import_node_path.dirname)(out), { recursive: true });
751
+ (0, import_node_fs.writeFileSync)(out, file.contents, "utf8");
752
+ }
753
+ return target;
754
+ }
755
+ // Annotate the CommonJS export names for ESM import in node:
756
+ 0 && (module.exports = {
757
+ TEMPLATES,
758
+ scaffold
759
+ });
760
+ //# sourceMappingURL=index.cjs.map