mcp-inflight 0.2.3 → 0.3.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/README.md +58 -1
- package/dist/index.js +185 -126
- package/package.json +8 -8
package/README.md
CHANGED
|
@@ -49,7 +49,39 @@ The MCP server provides these tools:
|
|
|
49
49
|
|
|
50
50
|
## Supported Projects
|
|
51
51
|
|
|
52
|
-
Next.js
|
|
52
|
+
- **Next.js** (App Router and Pages Router)
|
|
53
|
+
- **Vite** (React, Vue, Svelte, etc.)
|
|
54
|
+
- **Create React App**
|
|
55
|
+
- **Node.js**
|
|
56
|
+
- **Static HTML**
|
|
57
|
+
|
|
58
|
+
## Features
|
|
59
|
+
|
|
60
|
+
### Binary File Support
|
|
61
|
+
|
|
62
|
+
The MCP server automatically handles binary files including:
|
|
63
|
+
|
|
64
|
+
- **Images**: PNG, JPG, JPEG, GIF, WebP, ICO, SVG, BMP, TIFF, AVIF
|
|
65
|
+
- **Fonts**: WOFF, WOFF2, TTF, EOT, OTF
|
|
66
|
+
- **Media**: MP3, MP4, WebM, OGG, WAV
|
|
67
|
+
- **Other**: PDF, ZIP
|
|
68
|
+
|
|
69
|
+
Binary files are base64 encoded during upload and properly decoded in the sandbox, ensuring your `/public` folder assets work correctly.
|
|
70
|
+
|
|
71
|
+
### Monorepo Support
|
|
72
|
+
|
|
73
|
+
Automatically detects and bundles workspace dependencies for monorepo projects using pnpm, npm, or yarn workspaces.
|
|
74
|
+
|
|
75
|
+
### Automatic Patching
|
|
76
|
+
|
|
77
|
+
The server automatically patches configuration files for CodeSandbox compatibility:
|
|
78
|
+
|
|
79
|
+
- **Vite**: Adds `allowedHosts` for CodeSandbox domains
|
|
80
|
+
- **Next.js**: Configures CSP headers to allow iframe embedding
|
|
81
|
+
|
|
82
|
+
### Large Project Support
|
|
83
|
+
|
|
84
|
+
Projects over 3MB are automatically chunked into smaller uploads to handle Vercel's serverless function body size limits.
|
|
53
85
|
|
|
54
86
|
## Slash Commands (Optional)
|
|
55
87
|
|
|
@@ -80,6 +112,31 @@ cp packages/mcp-inflight/commands/*.md ~/.claude/commands/
|
|
|
80
112
|
| `/share` | Share a project to InFlight (shortcut for the share tool) |
|
|
81
113
|
| `/inflight` | Menu for managing prototypes: list, sync, delete, login, logout |
|
|
82
114
|
|
|
115
|
+
## Troubleshooting
|
|
116
|
+
|
|
117
|
+
### Server Startup Timeout
|
|
118
|
+
|
|
119
|
+
If you see "Timeout: Waiting for server to start took longer than 120s", this usually means:
|
|
120
|
+
|
|
121
|
+
1. The project is large and takes a while to start
|
|
122
|
+
2. There's an error in the dev server startup
|
|
123
|
+
|
|
124
|
+
The deployment logs will show the exact command being used. Try running it locally to verify it works.
|
|
125
|
+
|
|
126
|
+
### Missing Images or Assets
|
|
127
|
+
|
|
128
|
+
If images from your `/public` folder aren't loading, ensure:
|
|
129
|
+
|
|
130
|
+
1. The file extension is in the supported binary file list
|
|
131
|
+
2. The file path is correct (paths are relative to project root)
|
|
132
|
+
|
|
133
|
+
### Authentication Issues
|
|
134
|
+
|
|
135
|
+
If you're getting authentication errors:
|
|
136
|
+
|
|
137
|
+
1. Run the `login` tool to re-authenticate
|
|
138
|
+
2. Check that your InFlight account is active
|
|
139
|
+
|
|
83
140
|
## License
|
|
84
141
|
|
|
85
142
|
MIT
|
package/dist/index.js
CHANGED
|
@@ -496,6 +496,52 @@ function detectProjectType(projectPath) {
|
|
|
496
496
|
// src/utils/file-utils.ts
|
|
497
497
|
import * as fs2 from "fs";
|
|
498
498
|
import * as path2 from "path";
|
|
499
|
+
var BINARY_EXTENSIONS = [
|
|
500
|
+
// Images
|
|
501
|
+
".png",
|
|
502
|
+
".jpg",
|
|
503
|
+
".jpeg",
|
|
504
|
+
".gif",
|
|
505
|
+
".webp",
|
|
506
|
+
".ico",
|
|
507
|
+
".svg",
|
|
508
|
+
".bmp",
|
|
509
|
+
".tiff",
|
|
510
|
+
".avif",
|
|
511
|
+
// Fonts
|
|
512
|
+
".woff",
|
|
513
|
+
".woff2",
|
|
514
|
+
".ttf",
|
|
515
|
+
".eot",
|
|
516
|
+
".otf",
|
|
517
|
+
// Other binary
|
|
518
|
+
".pdf",
|
|
519
|
+
".zip",
|
|
520
|
+
".mp3",
|
|
521
|
+
".mp4",
|
|
522
|
+
".webm",
|
|
523
|
+
".ogg",
|
|
524
|
+
".wav"
|
|
525
|
+
];
|
|
526
|
+
function isBinaryFile(filename) {
|
|
527
|
+
const ext = path2.extname(filename).toLowerCase();
|
|
528
|
+
return BINARY_EXTENSIONS.includes(ext);
|
|
529
|
+
}
|
|
530
|
+
function getFileContent(file) {
|
|
531
|
+
return typeof file === "string" ? file : file.content;
|
|
532
|
+
}
|
|
533
|
+
function getFileSize(file) {
|
|
534
|
+
return getFileContent(file).length;
|
|
535
|
+
}
|
|
536
|
+
function getTextContent(file) {
|
|
537
|
+
if (typeof file === "string") {
|
|
538
|
+
return file;
|
|
539
|
+
}
|
|
540
|
+
if (file.encoding === "utf-8") {
|
|
541
|
+
return file.content;
|
|
542
|
+
}
|
|
543
|
+
return void 0;
|
|
544
|
+
}
|
|
499
545
|
var ALWAYS_IGNORE = [
|
|
500
546
|
"node_modules",
|
|
501
547
|
".git",
|
|
@@ -536,8 +582,15 @@ function readProjectFiles(projectPath, relativePath = "", includeEnvFiles = fals
|
|
|
536
582
|
} else if (entry.isFile()) {
|
|
537
583
|
const filePath = path2.join(projectPath, entryRelativePath);
|
|
538
584
|
try {
|
|
539
|
-
|
|
540
|
-
|
|
585
|
+
if (isBinaryFile(entry.name)) {
|
|
586
|
+
const buffer = fs2.readFileSync(filePath);
|
|
587
|
+
const content = buffer.toString("base64");
|
|
588
|
+
console.log(`[MCP] Read binary file: ${entryRelativePath}, original size=${buffer.length}, base64 length=${content.length}`);
|
|
589
|
+
files[entryRelativePath] = { content, encoding: "base64" };
|
|
590
|
+
} else {
|
|
591
|
+
const content = fs2.readFileSync(filePath, "utf-8");
|
|
592
|
+
files[entryRelativePath] = content;
|
|
593
|
+
}
|
|
541
594
|
} catch {
|
|
542
595
|
}
|
|
543
596
|
}
|
|
@@ -547,7 +600,7 @@ function readProjectFiles(projectPath, relativePath = "", includeEnvFiles = fals
|
|
|
547
600
|
var MAX_CHUNK_SIZE = 2 * 1024 * 1024;
|
|
548
601
|
var CHUNK_THRESHOLD = 3 * 1024 * 1024;
|
|
549
602
|
function calculateTotalSize(files) {
|
|
550
|
-
return Object.values(files).reduce((sum,
|
|
603
|
+
return Object.values(files).reduce((sum, file) => sum + getFileSize(file), 0);
|
|
551
604
|
}
|
|
552
605
|
function needsChunkedUpload(files) {
|
|
553
606
|
return calculateTotalSize(files) > CHUNK_THRESHOLD;
|
|
@@ -556,16 +609,16 @@ function chunkFiles(files, maxChunkSize = MAX_CHUNK_SIZE) {
|
|
|
556
609
|
const chunks = [];
|
|
557
610
|
let currentChunk = {};
|
|
558
611
|
let currentSize = 0;
|
|
559
|
-
const entries = Object.entries(files).sort((a, b) => a[1]
|
|
560
|
-
for (const [filePath,
|
|
561
|
-
const fileSize =
|
|
612
|
+
const entries = Object.entries(files).sort((a, b) => getFileSize(a[1]) - getFileSize(b[1]));
|
|
613
|
+
for (const [filePath, file] of entries) {
|
|
614
|
+
const fileSize = getFileSize(file);
|
|
562
615
|
if (fileSize > maxChunkSize) {
|
|
563
616
|
if (Object.keys(currentChunk).length > 0) {
|
|
564
617
|
chunks.push(currentChunk);
|
|
565
618
|
currentChunk = {};
|
|
566
619
|
currentSize = 0;
|
|
567
620
|
}
|
|
568
|
-
chunks.push({ [filePath]:
|
|
621
|
+
chunks.push({ [filePath]: file });
|
|
569
622
|
continue;
|
|
570
623
|
}
|
|
571
624
|
if (currentSize + fileSize > maxChunkSize && Object.keys(currentChunk).length > 0) {
|
|
@@ -573,7 +626,7 @@ function chunkFiles(files, maxChunkSize = MAX_CHUNK_SIZE) {
|
|
|
573
626
|
currentChunk = {};
|
|
574
627
|
currentSize = 0;
|
|
575
628
|
}
|
|
576
|
-
currentChunk[filePath] =
|
|
629
|
+
currentChunk[filePath] = file;
|
|
577
630
|
currentSize += fileSize;
|
|
578
631
|
}
|
|
579
632
|
if (Object.keys(currentChunk).length > 0) {
|
|
@@ -933,7 +986,8 @@ async function deployProject(files, options, log) {
|
|
|
933
986
|
vmTier: options.vmTier || "Micro",
|
|
934
987
|
projectName: options.projectName,
|
|
935
988
|
workspaceId: options.workspaceId || auth.defaultWorkspaceId,
|
|
936
|
-
gitInfo: options.gitInfo
|
|
989
|
+
gitInfo: options.gitInfo,
|
|
990
|
+
diffSummary: options.diffSummary
|
|
937
991
|
})
|
|
938
992
|
});
|
|
939
993
|
if (!response.ok && !response.headers.get("content-type")?.includes("text/event-stream")) {
|
|
@@ -1125,7 +1179,7 @@ async function uploadChunk(sandboxId, files, chunkIndex, totalChunks, log) {
|
|
|
1125
1179
|
throw new NotAuthenticatedError();
|
|
1126
1180
|
}
|
|
1127
1181
|
const fileCount = Object.keys(files).length;
|
|
1128
|
-
const chunkSize =
|
|
1182
|
+
const chunkSize = calculateTotalSize(files);
|
|
1129
1183
|
await log(`Uploading chunk ${chunkIndex + 1}/${totalChunks} (${fileCount} files, ${(chunkSize / 1024).toFixed(1)} KB)...`);
|
|
1130
1184
|
const response = await fetch(`${INFLIGHT_API}/api/mcp/sandbox/${sandboxId}/upload`, {
|
|
1131
1185
|
method: "POST",
|
|
@@ -1174,7 +1228,8 @@ async function finalizeSandbox(sandboxId, options, log) {
|
|
|
1174
1228
|
port: options.port,
|
|
1175
1229
|
projectName: options.projectName,
|
|
1176
1230
|
workspaceId: options.workspaceId,
|
|
1177
|
-
gitInfo: options.gitInfo
|
|
1231
|
+
gitInfo: options.gitInfo,
|
|
1232
|
+
diffSummary: options.diffSummary
|
|
1178
1233
|
})
|
|
1179
1234
|
});
|
|
1180
1235
|
if (!response.ok && !response.headers.get("content-type")?.includes("text/event-stream")) {
|
|
@@ -1231,7 +1286,8 @@ async function deployProjectChunked(fileChunks, options, log) {
|
|
|
1231
1286
|
port: options.port,
|
|
1232
1287
|
projectName: options.projectName,
|
|
1233
1288
|
workspaceId,
|
|
1234
|
-
gitInfo: options.gitInfo
|
|
1289
|
+
gitInfo: options.gitInfo,
|
|
1290
|
+
diffSummary: options.diffSummary
|
|
1235
1291
|
},
|
|
1236
1292
|
log
|
|
1237
1293
|
);
|
|
@@ -1384,8 +1440,30 @@ function checkMiddleware(content, filePath) {
|
|
|
1384
1440
|
configFile: filePath
|
|
1385
1441
|
};
|
|
1386
1442
|
}
|
|
1443
|
+
function configAllowsCodeSandbox(content) {
|
|
1444
|
+
const literalRegex = /['"`](https?:\/\/[^\s'"`]+|[^'"`\s]+)['"`]/g;
|
|
1445
|
+
let match;
|
|
1446
|
+
while ((match = literalRegex.exec(content)) !== null) {
|
|
1447
|
+
const literal = match[1];
|
|
1448
|
+
let hostname = "";
|
|
1449
|
+
try {
|
|
1450
|
+
if (/^https?:\/\//i.test(literal)) {
|
|
1451
|
+
const url = new URL(literal);
|
|
1452
|
+
hostname = url.hostname.toLowerCase();
|
|
1453
|
+
} else {
|
|
1454
|
+
hostname = literal.toLowerCase();
|
|
1455
|
+
}
|
|
1456
|
+
} catch {
|
|
1457
|
+
hostname = literal.toLowerCase();
|
|
1458
|
+
}
|
|
1459
|
+
if (hostname === "csb.app" || hostname === "codesandbox.io" || hostname.endsWith(".csb.app") || hostname.endsWith(".codesandbox.io")) {
|
|
1460
|
+
return true;
|
|
1461
|
+
}
|
|
1462
|
+
}
|
|
1463
|
+
return false;
|
|
1464
|
+
}
|
|
1387
1465
|
function checkViteConfig(content, filePath) {
|
|
1388
|
-
if (
|
|
1466
|
+
if (configAllowsCodeSandbox(content)) {
|
|
1389
1467
|
return { canEmbed: true, issues: [], configFile: filePath };
|
|
1390
1468
|
}
|
|
1391
1469
|
const issues = [];
|
|
@@ -1579,7 +1657,11 @@ function patchFilesForEmbed(files) {
|
|
|
1579
1657
|
const patchedFiles = [];
|
|
1580
1658
|
const remainingIssues = [];
|
|
1581
1659
|
const result = { ...files };
|
|
1582
|
-
for (const [filePath,
|
|
1660
|
+
for (const [filePath, file] of Object.entries(files)) {
|
|
1661
|
+
const content = getTextContent(file);
|
|
1662
|
+
if (content === void 0) {
|
|
1663
|
+
continue;
|
|
1664
|
+
}
|
|
1583
1665
|
const fileName = filePath.split("/").pop() || "";
|
|
1584
1666
|
let patched = null;
|
|
1585
1667
|
if (isMiddlewareFile(filePath)) {
|
|
@@ -1641,7 +1723,11 @@ function patchFilesForEmbed(files) {
|
|
|
1641
1723
|
}
|
|
1642
1724
|
function checkEmbedCompatibility(files) {
|
|
1643
1725
|
const allIssues = [];
|
|
1644
|
-
for (const [filePath,
|
|
1726
|
+
for (const [filePath, file] of Object.entries(files)) {
|
|
1727
|
+
const content = getTextContent(file);
|
|
1728
|
+
if (content === void 0) {
|
|
1729
|
+
continue;
|
|
1730
|
+
}
|
|
1645
1731
|
const fileName = filePath.split("/").pop() || "";
|
|
1646
1732
|
if (fileName === "next.config.js" || fileName === "next.config.mjs" || fileName === "next.config.ts") {
|
|
1647
1733
|
const result = checkNextConfig(content, filePath);
|
|
@@ -1843,6 +1929,9 @@ async function deployPrototype(args, log) {
|
|
|
1843
1929
|
const dirtyMarker = gitInfo.isDirty ? " (modified)" : "";
|
|
1844
1930
|
await log(`Git: ${gitInfo.branch}@${gitInfo.commitShort}${dirtyMarker}`);
|
|
1845
1931
|
}
|
|
1932
|
+
if (args.diffSummary) {
|
|
1933
|
+
await log(`Diff summary provided: ${args.diffSummary.keyChanges.length} key changes`);
|
|
1934
|
+
}
|
|
1846
1935
|
if (!projectInfo.compatibility.canDeploy) {
|
|
1847
1936
|
throw new Error(
|
|
1848
1937
|
`Project cannot be deployed: ${projectInfo.compatibility.issues.join(", ")}`
|
|
@@ -1912,126 +2001,76 @@ async function deployPrototype(args, log) {
|
|
|
1912
2001
|
}
|
|
1913
2002
|
}
|
|
1914
2003
|
}
|
|
1915
|
-
const totalSize =
|
|
2004
|
+
const totalSize = calculateTotalSize(files);
|
|
1916
2005
|
await log(`Found ${fileCount} files (${(totalSize / 1024 / 1024).toFixed(1)} MB)`);
|
|
1917
|
-
let existingSandbox;
|
|
1918
|
-
try {
|
|
1919
|
-
const sandboxes = await listSandboxes();
|
|
1920
|
-
const projectName = path5.basename(projectPath);
|
|
1921
|
-
existingSandbox = sandboxes.find(
|
|
1922
|
-
(s) => s.projectName === projectName && s.status === "running"
|
|
1923
|
-
);
|
|
1924
|
-
} catch {
|
|
1925
|
-
}
|
|
1926
2006
|
let result;
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
startCommand: projectInfo.startCommand,
|
|
1937
|
-
port: projectInfo.port,
|
|
1938
|
-
gitInfo: gitInfo || void 0
|
|
1939
|
-
},
|
|
1940
|
-
log
|
|
1941
|
-
);
|
|
1942
|
-
const inflightUrl = existingSandbox.inflightUrl || "";
|
|
1943
|
-
const inflightVersionId = existingSandbox.inflightVersionId || "";
|
|
1944
|
-
result = {
|
|
1945
|
-
url: syncResult.sandboxUrl,
|
|
1946
|
-
sandboxId: existingSandbox.sandboxId,
|
|
1947
|
-
projectType: projectInfo.type,
|
|
1948
|
-
synced: true,
|
|
1949
|
-
inflightUrl,
|
|
1950
|
-
inflightVersionId,
|
|
1951
|
-
startCommand: projectInfo.startCommand,
|
|
1952
|
-
port: projectInfo.port,
|
|
1953
|
-
packageManager: projectInfo.detectedPackageManager,
|
|
1954
|
-
isMonorepo: projectInfo.isMonorepo,
|
|
1955
|
-
vmTier: projectInfo.sizing.recommendedTier,
|
|
1956
|
-
embedCheck
|
|
1957
|
-
};
|
|
1958
|
-
const elapsed = ((Date.now() - startTime) / 1e3).toFixed(1);
|
|
1959
|
-
await log(`Sync complete in ${elapsed}s`);
|
|
1960
|
-
} catch (syncError) {
|
|
1961
|
-
const errorMsg = syncError instanceof Error ? syncError.message : String(syncError);
|
|
1962
|
-
await log(`Sync failed, creating new sandbox: ${errorMsg}`, "warning");
|
|
1963
|
-
existingSandbox = void 0;
|
|
1964
|
-
}
|
|
1965
|
-
}
|
|
1966
|
-
if (!existingSandbox) {
|
|
1967
|
-
const useChunkedUpload = needsChunkedUpload(files);
|
|
1968
|
-
if (useChunkedUpload) {
|
|
1969
|
-
const totalSize2 = calculateTotalSize(files);
|
|
1970
|
-
await log(`Large project detected (${(totalSize2 / 1024 / 1024).toFixed(1)} MB), using chunked upload...`);
|
|
1971
|
-
const fileChunks = chunkFiles(files);
|
|
1972
|
-
await log(`Split into ${fileChunks.length} chunks`);
|
|
1973
|
-
const deployResult = await deployProjectChunked(
|
|
1974
|
-
fileChunks,
|
|
1975
|
-
{
|
|
1976
|
-
projectType: projectInfo.type,
|
|
1977
|
-
installCommand: projectInfo.installCommand || void 0,
|
|
1978
|
-
startCommand: projectInfo.startCommand,
|
|
1979
|
-
port: projectInfo.port,
|
|
1980
|
-
vmTier: projectInfo.sizing.recommendedTier,
|
|
1981
|
-
projectName: path5.basename(projectPath),
|
|
1982
|
-
workspaceId: args.workspaceId,
|
|
1983
|
-
gitInfo: gitInfo || void 0
|
|
1984
|
-
},
|
|
1985
|
-
log
|
|
1986
|
-
);
|
|
1987
|
-
result = {
|
|
1988
|
-
url: deployResult.sandboxUrl,
|
|
1989
|
-
sandboxId: deployResult.sandboxId,
|
|
2007
|
+
const useChunkedUpload = needsChunkedUpload(files);
|
|
2008
|
+
if (useChunkedUpload) {
|
|
2009
|
+
const totalSize2 = calculateTotalSize(files);
|
|
2010
|
+
await log(`Large project detected (${(totalSize2 / 1024 / 1024).toFixed(1)} MB), using chunked upload...`);
|
|
2011
|
+
const fileChunks = chunkFiles(files);
|
|
2012
|
+
await log(`Split into ${fileChunks.length} chunks`);
|
|
2013
|
+
const deployResult = await deployProjectChunked(
|
|
2014
|
+
fileChunks,
|
|
2015
|
+
{
|
|
1990
2016
|
projectType: projectInfo.type,
|
|
1991
|
-
|
|
1992
|
-
inflightUrl: deployResult.inflightUrl,
|
|
1993
|
-
inflightVersionId: deployResult.versionId,
|
|
2017
|
+
installCommand: projectInfo.installCommand || void 0,
|
|
1994
2018
|
startCommand: projectInfo.startCommand,
|
|
1995
2019
|
port: projectInfo.port,
|
|
1996
|
-
packageManager: projectInfo.detectedPackageManager,
|
|
1997
|
-
isMonorepo: projectInfo.isMonorepo,
|
|
1998
2020
|
vmTier: projectInfo.sizing.recommendedTier,
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2021
|
+
projectName: path5.basename(projectPath),
|
|
2022
|
+
workspaceId: args.workspaceId,
|
|
2023
|
+
gitInfo: gitInfo || void 0,
|
|
2024
|
+
diffSummary: args.diffSummary || void 0
|
|
2025
|
+
},
|
|
2026
|
+
log
|
|
2027
|
+
);
|
|
2028
|
+
result = {
|
|
2029
|
+
url: deployResult.sandboxUrl,
|
|
2030
|
+
sandboxId: deployResult.sandboxId,
|
|
2031
|
+
projectType: projectInfo.type,
|
|
2032
|
+
inflightUrl: deployResult.inflightUrl,
|
|
2033
|
+
inflightVersionId: deployResult.versionId,
|
|
2034
|
+
startCommand: projectInfo.startCommand,
|
|
2035
|
+
port: projectInfo.port,
|
|
2036
|
+
packageManager: projectInfo.detectedPackageManager,
|
|
2037
|
+
isMonorepo: projectInfo.isMonorepo,
|
|
2038
|
+
vmTier: projectInfo.sizing.recommendedTier,
|
|
2039
|
+
embedCheck
|
|
2040
|
+
};
|
|
2041
|
+
} else {
|
|
2042
|
+
await log("Deploying via InFlight API...");
|
|
2043
|
+
const deployResult = await deployProject(
|
|
2044
|
+
files,
|
|
2045
|
+
{
|
|
2020
2046
|
projectType: projectInfo.type,
|
|
2021
|
-
|
|
2022
|
-
inflightUrl: deployResult.inflightUrl,
|
|
2023
|
-
inflightVersionId: deployResult.versionId,
|
|
2047
|
+
installCommand: projectInfo.installCommand || void 0,
|
|
2024
2048
|
startCommand: projectInfo.startCommand,
|
|
2025
2049
|
port: projectInfo.port,
|
|
2026
|
-
packageManager: projectInfo.detectedPackageManager,
|
|
2027
|
-
isMonorepo: projectInfo.isMonorepo,
|
|
2028
2050
|
vmTier: projectInfo.sizing.recommendedTier,
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2051
|
+
projectName: path5.basename(projectPath),
|
|
2052
|
+
workspaceId: args.workspaceId,
|
|
2053
|
+
gitInfo: gitInfo || void 0,
|
|
2054
|
+
diffSummary: args.diffSummary || void 0
|
|
2055
|
+
},
|
|
2056
|
+
log
|
|
2057
|
+
);
|
|
2058
|
+
result = {
|
|
2059
|
+
url: deployResult.sandboxUrl,
|
|
2060
|
+
sandboxId: deployResult.sandboxId,
|
|
2061
|
+
projectType: projectInfo.type,
|
|
2062
|
+
inflightUrl: deployResult.inflightUrl,
|
|
2063
|
+
inflightVersionId: deployResult.versionId,
|
|
2064
|
+
startCommand: projectInfo.startCommand,
|
|
2065
|
+
port: projectInfo.port,
|
|
2066
|
+
packageManager: projectInfo.detectedPackageManager,
|
|
2067
|
+
isMonorepo: projectInfo.isMonorepo,
|
|
2068
|
+
vmTier: projectInfo.sizing.recommendedTier,
|
|
2069
|
+
embedCheck
|
|
2070
|
+
};
|
|
2034
2071
|
}
|
|
2072
|
+
const elapsed = ((Date.now() - startTime) / 1e3).toFixed(1);
|
|
2073
|
+
await log(`Deploy complete in ${elapsed}s`);
|
|
2035
2074
|
if (hadUncommittedChanges && result.inflightVersionId) {
|
|
2036
2075
|
const newCommit = autoCommitForShare(projectPath, result.inflightVersionId);
|
|
2037
2076
|
if (newCommit) {
|
|
@@ -2105,6 +2144,27 @@ function createServer2() {
|
|
|
2105
2144
|
workspaceId: {
|
|
2106
2145
|
type: "string",
|
|
2107
2146
|
description: "InFlight workspace ID to create the version in. If not provided, uses the last-used workspace or the user's first workspace."
|
|
2147
|
+
},
|
|
2148
|
+
diffSummary: {
|
|
2149
|
+
type: "object",
|
|
2150
|
+
description: "Claude-generated summary of git changes for review question generation. Provide this when sharing a feature branch with commits.",
|
|
2151
|
+
properties: {
|
|
2152
|
+
summary: {
|
|
2153
|
+
type: "string",
|
|
2154
|
+
description: "A 2-3 sentence product-focused summary of the changes. Focus on user-visible changes, not internal code details."
|
|
2155
|
+
},
|
|
2156
|
+
keyChanges: {
|
|
2157
|
+
type: "array",
|
|
2158
|
+
items: { type: "string" },
|
|
2159
|
+
description: "List of key user-visible changes (e.g., 'Added dark mode toggle', 'Redesigned checkout flow')"
|
|
2160
|
+
},
|
|
2161
|
+
affectedAreas: {
|
|
2162
|
+
type: "array",
|
|
2163
|
+
items: { type: "string" },
|
|
2164
|
+
description: "UI/feature areas affected by the changes (e.g., 'Settings page', 'Navigation', 'Forms')"
|
|
2165
|
+
}
|
|
2166
|
+
},
|
|
2167
|
+
required: ["summary", "keyChanges"]
|
|
2108
2168
|
}
|
|
2109
2169
|
},
|
|
2110
2170
|
required: ["path"]
|
|
@@ -2179,7 +2239,7 @@ function createServer2() {
|
|
|
2179
2239
|
if (name === "share") {
|
|
2180
2240
|
const deployArgs = args;
|
|
2181
2241
|
const result = await deployPrototype(deployArgs, log);
|
|
2182
|
-
const message =
|
|
2242
|
+
const message = `Project shared successfully. InFlight: ${result.inflightUrl}`;
|
|
2183
2243
|
return {
|
|
2184
2244
|
content: [
|
|
2185
2245
|
{
|
|
@@ -2198,7 +2258,6 @@ function createServer2() {
|
|
|
2198
2258
|
},
|
|
2199
2259
|
// Embed check results - shows if there are iframe embedding issues
|
|
2200
2260
|
embedCheck: result.embedCheck,
|
|
2201
|
-
synced: result.synced ?? false,
|
|
2202
2261
|
inflightUrl: result.inflightUrl,
|
|
2203
2262
|
inflightVersionId: result.inflightVersionId,
|
|
2204
2263
|
message
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcp-inflight",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "MCP server for sharing prototypes via InFlight",
|
|
5
5
|
"author": "InFlight <hello@inflight.co>",
|
|
6
6
|
"homepage": "https://github.com/inflight/mcp-inflight",
|
|
@@ -13,11 +13,6 @@
|
|
|
13
13
|
"bin": {
|
|
14
14
|
"mcp-inflight": "dist/index.js"
|
|
15
15
|
},
|
|
16
|
-
"scripts": {
|
|
17
|
-
"build": "tsup",
|
|
18
|
-
"dev": "tsup --watch",
|
|
19
|
-
"typecheck": "tsc --noEmit"
|
|
20
|
-
},
|
|
21
16
|
"dependencies": {
|
|
22
17
|
"@modelcontextprotocol/sdk": "^1.0.0"
|
|
23
18
|
},
|
|
@@ -36,5 +31,10 @@
|
|
|
36
31
|
"share",
|
|
37
32
|
"deploy"
|
|
38
33
|
],
|
|
39
|
-
"license": "MIT"
|
|
40
|
-
|
|
34
|
+
"license": "MIT",
|
|
35
|
+
"scripts": {
|
|
36
|
+
"build": "tsup",
|
|
37
|
+
"dev": "tsup --watch",
|
|
38
|
+
"typecheck": "tsc --noEmit"
|
|
39
|
+
}
|
|
40
|
+
}
|