@leanmcp/cli 0.5.0 → 0.5.2-alpha.6.6dae082

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/bin/leanmcp.js CHANGED
@@ -1,4 +1,4 @@
1
1
  #!/usr/bin/env node
2
-
3
- // Always prefer ESM build
4
- import('../dist/index.js');
2
+
3
+ // Always prefer ESM build
4
+ import('../dist/index.js');
package/dist/index.js CHANGED
@@ -397,7 +397,7 @@ createRoot(document.getElementById('root')!).render(
397
397
  resolve: {
398
398
  alias: {
399
399
  // Resolve React from project or workspace root node_modules
400
- "react": reactPath,
400
+ react: reactPath,
401
401
  "react-dom": reactDomPath,
402
402
  "react/jsx-runtime": path2.join(reactPath, "jsx-runtime"),
403
403
  "react/jsx-dev-runtime": path2.join(reactPath, "jsx-dev-runtime")
@@ -1132,7 +1132,7 @@ async function loginCommand() {
1132
1132
  const response = await fetch(validateUrl, {
1133
1133
  method: "GET",
1134
1134
  headers: {
1135
- "Authorization": `Bearer ${apiKey.trim()}`,
1135
+ Authorization: `Bearer ${apiKey.trim()}`,
1136
1136
  "Content-Type": "application/json"
1137
1137
  }
1138
1138
  });
@@ -1219,7 +1219,7 @@ async function whoamiCommand() {
1219
1219
  const response = await fetch(whoamiUrl, {
1220
1220
  method: "GET",
1221
1221
  headers: {
1222
- "Authorization": `Bearer ${config.apiKey}`,
1222
+ Authorization: `Bearer ${config.apiKey}`,
1223
1223
  "Content-Type": "application/json"
1224
1224
  }
1225
1225
  });
@@ -1671,7 +1671,7 @@ async function waitForBuild(apiUrl, apiKey, buildId, spinner) {
1671
1671
  while (attempts < maxAttempts) {
1672
1672
  const response = await debugFetch(`${apiUrl}${API_ENDPOINTS.getBuild}/${buildId}`, {
1673
1673
  headers: {
1674
- "Authorization": `Bearer ${apiKey}`
1674
+ Authorization: `Bearer ${apiKey}`
1675
1675
  }
1676
1676
  });
1677
1677
  if (!response.ok) {
@@ -1700,7 +1700,7 @@ async function waitForDeployment(apiUrl, apiKey, deploymentId, spinner) {
1700
1700
  while (attempts < maxAttempts) {
1701
1701
  const response = await debugFetch(`${apiUrl}${API_ENDPOINTS.getDeployment}/${deploymentId}`, {
1702
1702
  headers: {
1703
- "Authorization": `Bearer ${apiKey}`
1703
+ Authorization: `Bearer ${apiKey}`
1704
1704
  }
1705
1705
  });
1706
1706
  if (!response.ok) {
@@ -1742,9 +1742,14 @@ async function deployCommand(folderPath, options = {}) {
1742
1742
  }
1743
1743
  const hasMainTs = await fs8.pathExists(path8.join(absolutePath, "main.ts"));
1744
1744
  const hasPackageJson = await fs8.pathExists(path8.join(absolutePath, "package.json"));
1745
- if (!hasMainTs && !hasPackageJson) {
1745
+ const hasMainPy = await fs8.pathExists(path8.join(absolutePath, "main.py"));
1746
+ const hasRequirementsTxt = await fs8.pathExists(path8.join(absolutePath, "requirements.txt"));
1747
+ const hasPyprojectToml = await fs8.pathExists(path8.join(absolutePath, "pyproject.toml"));
1748
+ const isNodeProject = hasMainTs || hasPackageJson;
1749
+ const isPythonProject = hasMainPy || hasRequirementsTxt || hasPyprojectToml;
1750
+ if (!isNodeProject && !isPythonProject) {
1746
1751
  logger.error("Not a valid project folder.");
1747
- logger.gray("Expected main.ts or package.json in the folder.\n");
1752
+ logger.gray("Expected one of: main.ts, package.json, main.py, requirements.txt, or pyproject.toml\n");
1748
1753
  process.exit(1);
1749
1754
  }
1750
1755
  const existingConfig = await readLeanMCPConfig(absolutePath);
@@ -1801,7 +1806,7 @@ Generated project name: ${chalk.bold(projectName)}
1801
1806
  try {
1802
1807
  const projectsResponse = await debugFetch(`${apiUrl}${API_ENDPOINTS.projects}`, {
1803
1808
  headers: {
1804
- "Authorization": `Bearer ${apiKey}`
1809
+ Authorization: `Bearer ${apiKey}`
1805
1810
  }
1806
1811
  });
1807
1812
  if (projectsResponse.ok) {
@@ -1887,7 +1892,7 @@ Generated project name: ${chalk.bold(projectName)}
1887
1892
  debug3("Checking subdomain:", subdomain);
1888
1893
  const checkResponse = await debugFetch(`${apiUrl}${API_ENDPOINTS.checkSubdomain}/${subdomain}`, {
1889
1894
  headers: {
1890
- "Authorization": `Bearer ${apiKey}`
1895
+ Authorization: `Bearer ${apiKey}`
1891
1896
  }
1892
1897
  });
1893
1898
  if (checkResponse.ok) {
@@ -1942,7 +1947,7 @@ This subdomain is associated with project: ${result.ownedByProject?.substring(0,
1942
1947
  const createResponse = await debugFetch(`${apiUrl}${API_ENDPOINTS.projects}`, {
1943
1948
  method: "POST",
1944
1949
  headers: {
1945
- "Authorization": `Bearer ${apiKey}`,
1950
+ Authorization: `Bearer ${apiKey}`,
1946
1951
  "Content-Type": "application/json"
1947
1952
  },
1948
1953
  body: JSON.stringify({
@@ -1972,7 +1977,7 @@ ${error instanceof Error ? error.message : String(error)}`);
1972
1977
  const uploadUrlResponse = await debugFetch(`${apiUrl}${API_ENDPOINTS.projects}/${projectId}/upload-url`, {
1973
1978
  method: "POST",
1974
1979
  headers: {
1975
- "Authorization": `Bearer ${apiKey}`,
1980
+ Authorization: `Bearer ${apiKey}`,
1976
1981
  "Content-Type": "application/json"
1977
1982
  },
1978
1983
  body: JSON.stringify({
@@ -2008,7 +2013,7 @@ ${error instanceof Error ? error.message : String(error)}`);
2008
2013
  await debugFetch(`${apiUrl}${API_ENDPOINTS.projects}/${projectId}`, {
2009
2014
  method: "PATCH",
2010
2015
  headers: {
2011
- "Authorization": `Bearer ${apiKey}`,
2016
+ Authorization: `Bearer ${apiKey}`,
2012
2017
  "Content-Type": "application/json"
2013
2018
  },
2014
2019
  body: JSON.stringify({
@@ -2032,7 +2037,7 @@ ${error instanceof Error ? error.message : String(error)}`);
2032
2037
  const buildResponse = await debugFetch(`${apiUrl}${API_ENDPOINTS.triggerBuild}/${projectId}`, {
2033
2038
  method: "POST",
2034
2039
  headers: {
2035
- "Authorization": `Bearer ${apiKey}`
2040
+ Authorization: `Bearer ${apiKey}`
2036
2041
  }
2037
2042
  });
2038
2043
  if (!buildResponse.ok) {
@@ -2059,7 +2064,7 @@ ${error instanceof Error ? error.message : String(error)}`);
2059
2064
  const deployResponse = await debugFetch(`${apiUrl}${API_ENDPOINTS.createDeployment}`, {
2060
2065
  method: "POST",
2061
2066
  headers: {
2062
- "Authorization": `Bearer ${apiKey}`,
2067
+ Authorization: `Bearer ${apiKey}`,
2063
2068
  "Content-Type": "application/json"
2064
2069
  },
2065
2070
  body: JSON.stringify({
@@ -2087,7 +2092,7 @@ ${error instanceof Error ? error.message : String(error)}`);
2087
2092
  const mappingResponse = await debugFetch(`${apiUrl}${API_ENDPOINTS.createMapping}`, {
2088
2093
  method: "POST",
2089
2094
  headers: {
2090
- "Authorization": `Bearer ${apiKey}`,
2095
+ Authorization: `Bearer ${apiKey}`,
2091
2096
  "Content-Type": "application/json"
2092
2097
  },
2093
2098
  body: JSON.stringify({
@@ -2160,7 +2165,7 @@ async function projectsListCommand() {
2160
2165
  const apiUrl = await getApiUrl();
2161
2166
  const response = await fetch(`${apiUrl}${API_ENDPOINT}`, {
2162
2167
  headers: {
2163
- "Authorization": `Bearer ${apiKey}`
2168
+ Authorization: `Bearer ${apiKey}`
2164
2169
  }
2165
2170
  });
2166
2171
  if (!response.ok) {
@@ -2205,7 +2210,7 @@ async function projectsGetCommand(projectId) {
2205
2210
  const apiUrl = await getApiUrl();
2206
2211
  const response = await fetch(`${apiUrl}${API_ENDPOINT}/${projectId}`, {
2207
2212
  headers: {
2208
- "Authorization": `Bearer ${apiKey}`
2213
+ Authorization: `Bearer ${apiKey}`
2209
2214
  }
2210
2215
  });
2211
2216
  if (!response.ok) {
@@ -2261,7 +2266,7 @@ async function projectsDeleteCommand(projectId, options = {}) {
2261
2266
  const response = await fetch(`${apiUrl}${API_ENDPOINT}/${projectId}`, {
2262
2267
  method: "DELETE",
2263
2268
  headers: {
2264
- "Authorization": `Bearer ${apiKey}`
2269
+ Authorization: `Bearer ${apiKey}`
2265
2270
  }
2266
2271
  });
2267
2272
  if (!response.ok) {
@@ -2370,7 +2375,7 @@ async function envListCommand(folderPath, options = {}) {
2370
2375
  const reveal = options.reveal ? "?reveal=true" : "";
2371
2376
  const response = await debugFetch2(`${apiUrl}/api/lambda-deploy/${config.deploymentId}/env${reveal}`, {
2372
2377
  headers: {
2373
- "Authorization": `Bearer ${apiKey}`
2378
+ Authorization: `Bearer ${apiKey}`
2374
2379
  }
2375
2380
  });
2376
2381
  if (!response.ok) {
@@ -2452,7 +2457,7 @@ ${error instanceof Error ? error.message : String(error)}`);
2452
2457
  const response = await debugFetch2(`${apiUrl}/api/lambda-deploy/${config.deploymentId}/env`, {
2453
2458
  method: "PUT",
2454
2459
  headers: {
2455
- "Authorization": `Bearer ${apiKey}`,
2460
+ Authorization: `Bearer ${apiKey}`,
2456
2461
  "Content-Type": "application/json"
2457
2462
  },
2458
2463
  body: JSON.stringify({
@@ -2486,7 +2491,7 @@ async function envGetCommand(key, folderPath, options = {}) {
2486
2491
  const reveal = options.reveal ? "?reveal=true" : "";
2487
2492
  const response = await debugFetch2(`${apiUrl}/api/lambda-deploy/${config.deploymentId}/env${reveal}`, {
2488
2493
  headers: {
2489
- "Authorization": `Bearer ${apiKey}`
2494
+ Authorization: `Bearer ${apiKey}`
2490
2495
  }
2491
2496
  });
2492
2497
  if (!response.ok) {
@@ -2537,7 +2542,7 @@ async function envRemoveCommand(key, folderPath, options = {}) {
2537
2542
  const response = await debugFetch2(`${apiUrl}/api/lambda-deploy/${config.deploymentId}/env/${key}`, {
2538
2543
  method: "DELETE",
2539
2544
  headers: {
2540
- "Authorization": `Bearer ${apiKey}`
2545
+ Authorization: `Bearer ${apiKey}`
2541
2546
  }
2542
2547
  });
2543
2548
  if (!response.ok) {
@@ -2565,7 +2570,7 @@ async function envPullCommand(folderPath, options = {}) {
2565
2570
  try {
2566
2571
  const response = await debugFetch2(`${apiUrl}/api/lambda-deploy/${config.deploymentId}/env?reveal=true`, {
2567
2572
  headers: {
2568
- "Authorization": `Bearer ${apiKey}`
2573
+ Authorization: `Bearer ${apiKey}`
2569
2574
  }
2570
2575
  });
2571
2576
  if (!response.ok) {
@@ -2632,7 +2637,7 @@ ${error instanceof Error ? error.message : String(error)}`);
2632
2637
  const response = await debugFetch2(`${apiUrl}/api/lambda-deploy/${config.deploymentId}/env`, {
2633
2638
  method: "PUT",
2634
2639
  headers: {
2635
- "Authorization": `Bearer ${apiKey}`,
2640
+ Authorization: `Bearer ${apiKey}`,
2636
2641
  "Content-Type": "application/json"
2637
2642
  },
2638
2643
  body: JSON.stringify({
@@ -3160,6 +3165,219 @@ export class ${capitalizedName}Service {
3160
3165
  }
3161
3166
  `, "getServiceIndexTemplate");
3162
3167
 
3168
+ // src/templates/python/main_py_v1.ts
3169
+ var getPythonMainTemplate = /* @__PURE__ */ __name((projectName) => `#!/usr/bin/env python3
3170
+ """
3171
+ ${projectName} - MCP Server with Streamable HTTP Transport
3172
+ """
3173
+ import os
3174
+ import uvicorn
3175
+ from dotenv import load_dotenv
3176
+ from mcp.server.fastmcp import FastMCP
3177
+
3178
+ # Load environment variables
3179
+ load_dotenv()
3180
+
3181
+ # Create the MCP server
3182
+ mcp = FastMCP("${projectName}")
3183
+
3184
+
3185
+ # === Define your tools, resources, and prompts below ===
3186
+
3187
+ @mcp.tool()
3188
+ def calculate(a: float, b: float, operation: str = "add") -> dict:
3189
+ """
3190
+ Perform arithmetic operations.
3191
+
3192
+ Args:
3193
+ a: First number
3194
+ b: Second number
3195
+ operation: Operation to perform (add, subtract, multiply, divide)
3196
+ """
3197
+ if operation == "add":
3198
+ result = a + b
3199
+ elif operation == "subtract":
3200
+ result = a - b
3201
+ elif operation == "multiply":
3202
+ result = a * b
3203
+ elif operation == "divide":
3204
+ if b == 0:
3205
+ raise ValueError("Cannot divide by zero")
3206
+ result = a / b
3207
+ else:
3208
+ raise ValueError(f"Invalid operation: {operation}")
3209
+
3210
+ return {"operation": operation, "a": a, "b": b, "result": result}
3211
+
3212
+
3213
+ @mcp.tool()
3214
+ def echo(message: str) -> dict:
3215
+ """Echo a message back with a timestamp."""
3216
+ from datetime import datetime
3217
+ return {"echoed": message, "timestamp": datetime.now().isoformat()}
3218
+
3219
+
3220
+ @mcp.resource("server://info")
3221
+ def server_info() -> str:
3222
+ """Get server information."""
3223
+ import json
3224
+ import time
3225
+ return json.dumps({
3226
+ "name": "${projectName}",
3227
+ "version": "1.0.0",
3228
+ "uptime": time.process_time()
3229
+ }, indent=2)
3230
+
3231
+
3232
+ @mcp.prompt()
3233
+ def greeting(name: str = "there") -> str:
3234
+ """Generate a greeting prompt."""
3235
+ return f"Hello {name}! Welcome to ${projectName}."
3236
+
3237
+
3238
+ if __name__ == "__main__":
3239
+ port = int(os.getenv("PORT", "3001"))
3240
+ print(f"\\n${projectName} MCP Server starting on port {port}...")
3241
+
3242
+ # Run with streamable HTTP transport
3243
+ uvicorn.run(
3244
+ mcp.streamable_http_app(),
3245
+ host="127.0.0.1",
3246
+ port=port,
3247
+ log_level="info"
3248
+ )
3249
+ `, "getPythonMainTemplate");
3250
+
3251
+ // src/templates/python/requirements_v1.ts
3252
+ var getPythonRequirementsTemplate = /* @__PURE__ */ __name(() => `# MCP Server Dependencies
3253
+ mcp>=1.0.0
3254
+ fastmcp>=0.1.0
3255
+ uvicorn>=0.30.0
3256
+ python-dotenv>=1.0.0
3257
+ pydantic>=2.0.0
3258
+
3259
+ # Optional: Add your dependencies below
3260
+ # requests>=2.31.0
3261
+ # httpx>=0.27.0
3262
+ `, "getPythonRequirementsTemplate");
3263
+
3264
+ // src/templates/python/gitignore_py_v1.ts
3265
+ var pythonGitignoreTemplate = `# Byte-compiled / optimized / DLL files
3266
+ __pycache__/
3267
+ *.py[cod]
3268
+ *$py.class
3269
+
3270
+ # Virtual environments
3271
+ venv/
3272
+ .venv/
3273
+ ENV/
3274
+ env/
3275
+
3276
+ # Distribution / packaging
3277
+ build/
3278
+ dist/
3279
+ *.egg-info/
3280
+ *.egg
3281
+
3282
+ # IDE
3283
+ .idea/
3284
+ .vscode/
3285
+ *.swp
3286
+ *.swo
3287
+
3288
+ # Environment variables
3289
+ .env
3290
+ .env.local
3291
+ .env.*.local
3292
+
3293
+ # Testing
3294
+ .pytest_cache/
3295
+ .coverage
3296
+ htmlcov/
3297
+
3298
+ # Logs
3299
+ *.log
3300
+
3301
+ # OS
3302
+ .DS_Store
3303
+ Thumbs.db
3304
+ `;
3305
+
3306
+ // src/templates/python/readme_py_v1.ts
3307
+ var getPythonReadmeTemplate = /* @__PURE__ */ __name((projectName) => `# ${projectName}
3308
+
3309
+ A Python MCP (Model Context Protocol) server with Streamable HTTP transport.
3310
+
3311
+ ## Quick Start
3312
+
3313
+ ### Prerequisites
3314
+
3315
+ - Python 3.10+
3316
+ - pip or uv package manager
3317
+
3318
+ ### Installation
3319
+
3320
+ \`\`\`bash
3321
+ # Create virtual environment
3322
+ python -m venv venv
3323
+ source venv/bin/activate # On Windows: venv\\Scripts\\activate
3324
+
3325
+ # Install dependencies
3326
+ pip install -r requirements.txt
3327
+ \`\`\`
3328
+
3329
+ ### Development
3330
+
3331
+ \`\`\`bash
3332
+ # Start development server
3333
+ python main.py
3334
+ \`\`\`
3335
+
3336
+ Server runs at http://localhost:3001
3337
+
3338
+ ### Test with MCP Inspector
3339
+
3340
+ \`\`\`bash
3341
+ npx @modelcontextprotocol/inspector http://localhost:3001/mcp
3342
+ \`\`\`
3343
+
3344
+ ## Project Structure
3345
+
3346
+ \`\`\`
3347
+ ${projectName}/
3348
+ main.py # Server entry point with tools/resources/prompts
3349
+ requirements.txt # Python dependencies
3350
+ .env # Environment variables
3351
+ \`\`\`
3352
+
3353
+ ## Adding New Tools
3354
+
3355
+ Add tools directly in \`main.py\` using the \`@mcp.tool()\` decorator:
3356
+
3357
+ \`\`\`python
3358
+ @mcp.tool()
3359
+ def my_tool(param: str) -> dict:
3360
+ """Tool description shown to AI.
3361
+
3362
+ Args:
3363
+ param: Parameter description
3364
+ """
3365
+ return {"result": param}
3366
+ \`\`\`
3367
+
3368
+ ## Deploy to LeanMCP Cloud
3369
+
3370
+ \`\`\`bash
3371
+ leanmcp deploy .
3372
+ \`\`\`
3373
+
3374
+ ## Resources
3375
+
3376
+ - [MCP Documentation](https://modelcontextprotocol.io)
3377
+ - [FastMCP Documentation](https://github.com/jlowin/fastmcp)
3378
+ - [LeanMCP Documentation](https://docs.leanmcp.com)
3379
+ `, "getPythonReadmeTemplate");
3380
+
3163
3381
  // src/index.ts
3164
3382
  var require2 = createRequire(import.meta.url);
3165
3383
  var pkg = require2("../package.json");
@@ -3182,7 +3400,8 @@ __name(enableDebugIfNeeded, "enableDebugIfNeeded");
3182
3400
  enableDebugIfNeeded();
3183
3401
  program.name("leanmcp").description("LeanMCP CLI \u2014 create production-ready MCP servers with Streamable HTTP").version(pkg.version, "-v, --version", "Output the current version").helpOption("-h, --help", "Display help for command").option("-d, --debug", "Enable debug logging for all commands").addHelpText("after", `
3184
3402
  Examples:
3185
- $ leanmcp create my-app # Create new project (interactive)
3403
+ $ leanmcp create my-app # Create new TypeScript project (interactive)
3404
+ $ leanmcp create my-app --python # Create new Python project
3186
3405
  $ leanmcp create my-app -i # Create and install deps (non-interactive)
3187
3406
  $ leanmcp create my-app --no-install # Create without installing deps
3188
3407
  $ leanmcp dev # Start development server
@@ -3200,7 +3419,7 @@ Global Options:
3200
3419
  -h, --help Display help for command
3201
3420
  -d, --debug Enable debug logging for all commands
3202
3421
  `);
3203
- program.command("create <projectName>").description("Create a new LeanMCP project with Streamable HTTP transport").option("--allow-all", "Skip interactive confirmations and assume Yes").option("--no-dashboard", "Disable dashboard UI at / and /mcp GET endpoints").option("-i, --install", "Install dependencies automatically (non-interactive, no dev server)").option("--no-install", "Skip dependency installation (non-interactive)").action(async (projectName, options) => {
3422
+ program.command("create <projectName>").description("Create a new LeanMCP project with Streamable HTTP transport").option("--allow-all", "Skip interactive confirmations and assume Yes").option("--no-dashboard", "Disable dashboard UI at / and /mcp GET endpoints").option("-i, --install", "Install dependencies automatically (non-interactive, no dev server)").option("--no-install", "Skip dependency installation (non-interactive)").option("--python", "Create a Python MCP project instead of TypeScript").action(async (projectName, options) => {
3204
3423
  trackCommand("create", {
3205
3424
  projectName,
3206
3425
  ...options
@@ -3212,85 +3431,102 @@ program.command("create <projectName>").description("Create a new LeanMCP projec
3212
3431
  process.exit(1);
3213
3432
  }
3214
3433
  await fs10.mkdirp(targetDir);
3215
- await fs10.mkdirp(path10.join(targetDir, "mcp", "example"));
3216
- const pkg2 = {
3217
- name: projectName,
3218
- version: "1.0.0",
3219
- description: "MCP Server with Streamable HTTP Transport and LeanMCP SDK",
3220
- main: "dist/main.js",
3221
- type: "module",
3222
- scripts: {
3223
- dev: "leanmcp dev",
3224
- build: "leanmcp build",
3225
- start: "leanmcp start",
3226
- inspect: "npx @modelcontextprotocol/inspector node dist/main.js",
3227
- "start:node": "node dist/main.js",
3228
- clean: "rm -rf dist"
3229
- },
3230
- keywords: [
3231
- "mcp",
3232
- "model-context-protocol",
3233
- "streamable-http",
3234
- "leanmcp"
3235
- ],
3236
- author: "",
3237
- license: "MIT",
3238
- dependencies: {
3239
- "@leanmcp/core": "^0.3.14",
3240
- "@leanmcp/ui": "^0.2.1",
3241
- "@leanmcp/auth": "^0.4.0",
3242
- "dotenv": "^16.5.0"
3243
- },
3244
- devDependencies: {
3245
- "@leanmcp/cli": "^0.4.0",
3246
- "@types/node": "^20.0.0",
3247
- "tsx": "^4.20.3",
3248
- "typescript": "^5.6.3"
3249
- }
3250
- };
3251
- await fs10.writeJSON(path10.join(targetDir, "package.json"), pkg2, {
3252
- spaces: 2
3253
- });
3254
- const tsconfig = {
3255
- compilerOptions: {
3256
- module: "ESNext",
3257
- target: "ES2022",
3258
- moduleResolution: "Node",
3259
- esModuleInterop: true,
3260
- strict: true,
3261
- skipLibCheck: true,
3262
- outDir: "dist",
3263
- experimentalDecorators: true,
3264
- emitDecoratorMetadata: true
3265
- },
3266
- include: [
3267
- "**/*.ts"
3268
- ],
3269
- exclude: [
3270
- "node_modules",
3271
- "dist"
3272
- ]
3273
- };
3274
- await fs10.writeJSON(path10.join(targetDir, "tsconfig.json"), tsconfig, {
3275
- spaces: 2
3276
- });
3277
- const dashboardLine = options.dashboard === false ? `
3434
+ const isPython = options.python === true;
3435
+ if (isPython) {
3436
+ const requirements = getPythonRequirementsTemplate();
3437
+ await fs10.writeFile(path10.join(targetDir, "requirements.txt"), requirements);
3438
+ const mainPy = getPythonMainTemplate(projectName);
3439
+ await fs10.writeFile(path10.join(targetDir, "main.py"), mainPy);
3440
+ await fs10.writeFile(path10.join(targetDir, ".gitignore"), pythonGitignoreTemplate);
3441
+ const env = `# Server Configuration
3442
+ PORT=3001
3443
+
3444
+ # Add your environment variables here
3445
+ `;
3446
+ await fs10.writeFile(path10.join(targetDir, ".env"), env);
3447
+ const readme = getPythonReadmeTemplate(projectName);
3448
+ await fs10.writeFile(path10.join(targetDir, "README.md"), readme);
3449
+ } else {
3450
+ await fs10.mkdirp(path10.join(targetDir, "mcp", "example"));
3451
+ const pkg2 = {
3452
+ name: projectName,
3453
+ version: "1.0.0",
3454
+ description: "MCP Server with Streamable HTTP Transport and LeanMCP SDK",
3455
+ main: "dist/main.js",
3456
+ type: "module",
3457
+ scripts: {
3458
+ dev: "leanmcp dev",
3459
+ build: "leanmcp build",
3460
+ start: "leanmcp start",
3461
+ inspect: "npx @modelcontextprotocol/inspector node dist/main.js",
3462
+ "start:node": "node dist/main.js",
3463
+ clean: "rm -rf dist"
3464
+ },
3465
+ keywords: [
3466
+ "mcp",
3467
+ "model-context-protocol",
3468
+ "streamable-http",
3469
+ "leanmcp"
3470
+ ],
3471
+ author: "",
3472
+ license: "MIT",
3473
+ dependencies: {
3474
+ "@leanmcp/core": "^0.3.14",
3475
+ "@leanmcp/ui": "^0.2.1",
3476
+ "@leanmcp/auth": "^0.4.0",
3477
+ dotenv: "^16.5.0"
3478
+ },
3479
+ devDependencies: {
3480
+ "@leanmcp/cli": "^0.4.0",
3481
+ "@types/node": "^20.0.0",
3482
+ tsx: "^4.20.3",
3483
+ typescript: "^5.6.3"
3484
+ }
3485
+ };
3486
+ await fs10.writeJSON(path10.join(targetDir, "package.json"), pkg2, {
3487
+ spaces: 2
3488
+ });
3489
+ const tsconfig = {
3490
+ compilerOptions: {
3491
+ module: "ESNext",
3492
+ target: "ES2022",
3493
+ moduleResolution: "Node",
3494
+ esModuleInterop: true,
3495
+ strict: true,
3496
+ skipLibCheck: true,
3497
+ outDir: "dist",
3498
+ experimentalDecorators: true,
3499
+ emitDecoratorMetadata: true
3500
+ },
3501
+ include: [
3502
+ "**/*.ts"
3503
+ ],
3504
+ exclude: [
3505
+ "node_modules",
3506
+ "dist"
3507
+ ]
3508
+ };
3509
+ await fs10.writeJSON(path10.join(targetDir, "tsconfig.json"), tsconfig, {
3510
+ spaces: 2
3511
+ });
3512
+ const dashboardLine = options.dashboard === false ? `
3278
3513
  dashboard: false, // Dashboard disabled via --no-dashboard` : "";
3279
- const mainTs = getMainTsTemplate(projectName, dashboardLine);
3280
- await fs10.writeFile(path10.join(targetDir, "main.ts"), mainTs);
3281
- const exampleServiceTs = getExampleServiceTemplate(projectName);
3282
- await fs10.writeFile(path10.join(targetDir, "mcp", "example", "index.ts"), exampleServiceTs);
3283
- const gitignore = gitignoreTemplate;
3284
- const env = `# Server Configuration
3514
+ const mainTs = getMainTsTemplate(projectName, dashboardLine);
3515
+ await fs10.writeFile(path10.join(targetDir, "main.ts"), mainTs);
3516
+ const exampleServiceTs = getExampleServiceTemplate(projectName);
3517
+ await fs10.writeFile(path10.join(targetDir, "mcp", "example", "index.ts"), exampleServiceTs);
3518
+ const gitignore = gitignoreTemplate;
3519
+ const env = `# Server Configuration
3285
3520
  PORT=3001
3286
3521
  NODE_ENV=development
3287
3522
 
3288
3523
  # Add your environment variables here
3289
3524
  `;
3290
- await fs10.writeFile(path10.join(targetDir, ".gitignore"), gitignore);
3291
- await fs10.writeFile(path10.join(targetDir, ".env"), env);
3292
- const readme = getReadmeTemplate(projectName);
3293
- await fs10.writeFile(path10.join(targetDir, "README.md"), readme);
3525
+ await fs10.writeFile(path10.join(targetDir, ".gitignore"), gitignore);
3526
+ await fs10.writeFile(path10.join(targetDir, ".env"), env);
3527
+ const readme = getReadmeTemplate(projectName);
3528
+ await fs10.writeFile(path10.join(targetDir, "README.md"), readme);
3529
+ }
3294
3530
  spinner.succeed(`Project ${projectName} created!`);
3295
3531
  logger.log("\nSuccess! Your MCP server is ready.\n", chalk.green);
3296
3532
  logger.log("To deploy to LeanMCP cloud:", chalk.cyan);
@@ -3303,8 +3539,28 @@ NODE_ENV=development
3303
3539
  if (options.install === false) {
3304
3540
  logger.log("To get started:", chalk.cyan);
3305
3541
  logger.log(` cd ${projectName}`, chalk.gray);
3306
- logger.log(` npm install`, chalk.gray);
3307
- logger.log(` npm run dev`, chalk.gray);
3542
+ if (isPython) {
3543
+ logger.log(` python -m venv venv`, chalk.gray);
3544
+ logger.log(` source venv/bin/activate # On Windows: venv\\Scripts\\activate`, chalk.gray);
3545
+ logger.log(` pip install -r requirements.txt`, chalk.gray);
3546
+ logger.log(` python main.py`, chalk.gray);
3547
+ } else {
3548
+ logger.log(` npm install`, chalk.gray);
3549
+ logger.log(` npm run dev`, chalk.gray);
3550
+ }
3551
+ logger.log("");
3552
+ logger.log("To deploy to LeanMCP cloud:", chalk.cyan);
3553
+ logger.log(` cd ${projectName}`, chalk.gray);
3554
+ logger.log(` leanmcp deploy .`, chalk.gray);
3555
+ return;
3556
+ }
3557
+ if (isPython) {
3558
+ logger.log("\nTo get started:", chalk.cyan);
3559
+ logger.log(` cd ${projectName}`, chalk.gray);
3560
+ logger.log(` python -m venv venv`, chalk.gray);
3561
+ logger.log(` source venv/bin/activate # On Windows: venv\\Scripts\\activate`, chalk.gray);
3562
+ logger.log(` pip install -r requirements.txt`, chalk.gray);
3563
+ logger.log(` python main.py`, chalk.gray);
3308
3564
  logger.log("");
3309
3565
  logger.log("To deploy to LeanMCP cloud:", chalk.cyan);
3310
3566
  logger.log(` cd ${projectName}`, chalk.gray);