fix: enforce executable permissions on binary entry points during pack

When server.type is "binary", mcpb pack now ensures the entry_point
file has execute bits (|0o111) in the ZIP external_attr, regardless
of the source filesystem permissions. This prevents EACCES failures
when Claude Desktop extracts Windows-built binary MCPBs (which store
644 because Windows has no Unix execute bit).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Bryan Thompson 2026-03-27 09:18:30 -05:00
commit 122ef0e9e9
No known key found for this signature in database
GPG key ID: 1D66D91917EE02E6

View file

@ -206,15 +206,22 @@ export async function packExtension({
const zipFiles: Zippable = {};
const isUnix = process.platform !== "win32";
const isBinaryType = manifest.server?.type === "binary";
const binaryEntryPoint = isBinaryType ? manifest.server.entry_point : null;
for (const [filePath, fileData] of Object.entries(files)) {
if (isUnix) {
let mode = fileData.mode & 0o777;
// Ensure binary entry points are always executable in the ZIP,
// regardless of filesystem permissions. Windows-built ZIPs store
// 644 because Windows has no Unix execute bit — CD spawns binary
// entry points directly, so they must have +x to avoid EACCES.
if (binaryEntryPoint && filePath === binaryEntryPoint) {
mode = mode | 0o111;
}
// Set external file attributes to preserve Unix permissions
// The mode needs to be shifted to the upper 16 bits for ZIP format
zipFiles[filePath] = [
fileData.data,
{ os: 3, attrs: (fileData.mode & 0o777) << 16 },
];
zipFiles[filePath] = [fileData.data, { os: 3, attrs: mode << 16 }];
} else {
// On Windows, use default ZIP attributes (no Unix permissions)
zipFiles[filePath] = fileData.data;