@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/LICENSE +21 -21
- package/README.md +368 -353
- package/bin/leanmcp.js +3 -3
- package/dist/index.js +357 -101
- package/package.json +73 -73
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
3216
|
-
|
|
3217
|
-
|
|
3218
|
-
|
|
3219
|
-
|
|
3220
|
-
|
|
3221
|
-
|
|
3222
|
-
|
|
3223
|
-
|
|
3224
|
-
|
|
3225
|
-
|
|
3226
|
-
|
|
3227
|
-
|
|
3228
|
-
|
|
3229
|
-
|
|
3230
|
-
|
|
3231
|
-
|
|
3232
|
-
|
|
3233
|
-
|
|
3234
|
-
"
|
|
3235
|
-
|
|
3236
|
-
|
|
3237
|
-
|
|
3238
|
-
|
|
3239
|
-
|
|
3240
|
-
|
|
3241
|
-
|
|
3242
|
-
|
|
3243
|
-
|
|
3244
|
-
|
|
3245
|
-
|
|
3246
|
-
|
|
3247
|
-
|
|
3248
|
-
|
|
3249
|
-
|
|
3250
|
-
|
|
3251
|
-
|
|
3252
|
-
|
|
3253
|
-
|
|
3254
|
-
|
|
3255
|
-
|
|
3256
|
-
|
|
3257
|
-
|
|
3258
|
-
|
|
3259
|
-
|
|
3260
|
-
|
|
3261
|
-
|
|
3262
|
-
|
|
3263
|
-
|
|
3264
|
-
|
|
3265
|
-
|
|
3266
|
-
|
|
3267
|
-
|
|
3268
|
-
|
|
3269
|
-
|
|
3270
|
-
|
|
3271
|
-
|
|
3272
|
-
|
|
3273
|
-
|
|
3274
|
-
|
|
3275
|
-
|
|
3276
|
-
|
|
3277
|
-
|
|
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
|
-
|
|
3280
|
-
|
|
3281
|
-
|
|
3282
|
-
|
|
3283
|
-
|
|
3284
|
-
|
|
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
|
-
|
|
3291
|
-
|
|
3292
|
-
|
|
3293
|
-
|
|
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
|
-
|
|
3307
|
-
|
|
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);
|