Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,15 @@ plans/
planning/

# Test output files
test/test_output/
test/test_output/

# MCPB related files
*.mcpb
mcpb-bundle/
.mcpregistry_github_token
.mcpregistry_registry_token

# Test files
test_files/
test_fix.js
test_search.js
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -954,7 +954,7 @@ External telemetry (sent to analytics services) is enabled by default but can be

**Note:** This only disables external telemetry. Local usage analytics remain active for tool functionality but is not share externally

For complete details about data collection, please see our [Privacy Policy](PRIVACY.md).
For complete details about data collection, please see our [Privacy Policy](https://legal.desktopcommander.app/privacy_desktop_commander_mcp).

## Verifications
[![Verified on MseeP](https://mseep.ai/badge.svg)](https://mseep.ai/app/25ff7a06-58bc-40b8-bd79-ebb715140f1a)
Expand Down
Binary file added icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
61 changes: 61 additions & 0 deletions manifest.template.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
{
"manifest_version": "0.1",
"name": "desktop-commander",
"display_name": "Desktop Commander",
"version": "{{VERSION}}",
"description": "Complete AI development workflow orchestration - from file creation to testing and deployment through terminal and file operations",
"long_description": "Desktop Commander is the central orchestration hub for AI-powered development workflows. It enables AI assistants to seamlessly coordinate file operations, terminal commands, and system integration on your local machine. Whether you're a non-technical founder building your first prototype or a developer orchestrating complex multi-tool workflows, Desktop Commander provides the reliable foundation for end-to-end development. Trusted by thousands of users for rapid prototyping, system administration, and production workflows.",
"author": {
"name": "Desktop Commander Team",
"email": "er@desktopcommander.app",
"url": "https://desktopcommander.app/"
},
"repository": {
"type": "git",
"url": "https://github.com/wonderwhy-er/DesktopCommanderMCP.git"
},
"homepage": "https://github.com/wonderwhy-er/DesktopCommanderMCP",
"documentation": "https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/FAQ.md",
"support": "https://discord.com/channels/1353458235608137880/1361495231538921494",
"icon": "icon.png",
"server": {
"type": "node",
"entry_point": "dist/index.js",
"mcp_config": {
"command": "node",
"args": [
"${__dirname}/dist/index.js"
],
Comment on lines +25 to +29

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Fix the MCP command args path (literal ${__dirname} won’t resolve).

mcp_config.args is passed verbatim to the client process runner, so "${__dirname}/dist/index.js" remains a literal string and the launch fails with “ENOENT: no such file or directory, open '${__dirname}/dist/index.js'”. Use a relative path instead so the bundle starts correctly.

Apply this diff:

-        "${__dirname}/dist/index.js"
+        "./dist/index.js"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"mcp_config": {
"command": "node",
"args": [
"${__dirname}/dist/index.js"
],
"mcp_config": {
"command": "node",
"args": [
"./dist/index.js"
],
🤖 Prompt for AI Agents
In manifest.template.json around lines 24 to 28, the mcp_config.args entry uses
the literal string "${__dirname}/dist/index.js" which won’t be resolved at
runtime; replace that element with a relative path to the bundled entry (for
example "./dist/index.js" or "dist/index.js") so the node process can locate and
start the bundle correctly when invoked by the client process runner.

"env": {
"NODE_ENV": "production"
}
}
},
"keywords": [
"orchestration",
"workflow",
"development",
"prototyping",
"terminal",
"processes",
"file-management",
"automation",
"productivity",
"end-to-end",
"data-analysis"
],
"license": "MIT",
"privacy_policies": [
"https://legal.desktopcommander.app/privacy_desktop_commander_mcp"
],
"compatibility": {
"platforms": [
"darwin",
"win32",
"linux"
],
"runtimes": {
"node": ">=18.0.0"
}
}
}
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
"link:local": "npm run build && npm link",
"unlink:local": "npm unlink",
"inspector": "npx @modelcontextprotocol/inspector dist/index.js",
"build:mcpb": "node scripts/build-mcpb.cjs",
"logs:view": "npm run build && node scripts/view-fuzzy-logs.js",
"logs:analyze": "npm run build && node scripts/analyze-fuzzy-logs.js",
"logs:clear": "npm run build && node scripts/clear-fuzzy-logs.js",
Expand Down
168 changes: 168 additions & 0 deletions scripts/build-mcpb.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
#!/usr/bin/env node

/**
* Build script for creating Desktop Commander MCPB bundle
*
* This script:
* 1. Builds the TypeScript project
* 2. Creates a bundle directory structure
* 3. Generates a proper MCPB manifest.json
* 4. Copies the built server and dependencies
* 5. Uses mcpb CLI to create the final .mcpb bundle
*/

const fs = require('fs');
const path = require('path');
const { execSync } = require('child_process');

const PROJECT_ROOT = path.resolve(__dirname, '..');
const BUNDLE_DIR = path.join(PROJECT_ROOT, 'mcpb-bundle');
const MANIFEST_PATH = path.join(BUNDLE_DIR, 'manifest.json');

console.log('🏗️ Building Desktop Commander MCPB Bundle...');

// Step 1: Build the TypeScript project
console.log('📦 Building TypeScript project...');
try {
execSync('npm run build', { cwd: PROJECT_ROOT, stdio: 'inherit' });
console.log('✅ TypeScript build completed');
} catch (error) {
console.error('❌ TypeScript build failed:', error.message);
process.exit(1);
}

// Step 2: Clean and create bundle directory
if (fs.existsSync(BUNDLE_DIR)) {
fs.rmSync(BUNDLE_DIR, { recursive: true });
}fs.mkdirSync(BUNDLE_DIR, { recursive: true });

Comment on lines +35 to +38

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Fix bundle directory creation syntax error.

} and fs.mkdirSync are glued together (}fs), so the script dies with Unexpected identifier before doing any work. Split them so the bundle directory actually gets created.

 if (fs.existsSync(BUNDLE_DIR)) {
     fs.rmSync(BUNDLE_DIR, { recursive: true });
-}fs.mkdirSync(BUNDLE_DIR, { recursive: true });
+}
+fs.mkdirSync(BUNDLE_DIR, { recursive: true });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (fs.existsSync(BUNDLE_DIR)) {
fs.rmSync(BUNDLE_DIR, { recursive: true });
}fs.mkdirSync(BUNDLE_DIR, { recursive: true });
if (fs.existsSync(BUNDLE_DIR)) {
fs.rmSync(BUNDLE_DIR, { recursive: true });
}
fs.mkdirSync(BUNDLE_DIR, { recursive: true });
🤖 Prompt for AI Agents
In scripts/build-mcpb.cjs around lines 35 to 38, there's a syntax error caused
by `}` and `fs.mkdirSync` being concatenated (`}fs`) which throws an Unexpected
identifier; separate the statements by placing a semicolon or newline after the
closing brace so the fs.mkdirSync(BUNDLE_DIR, { recursive: true }) call is a
standalone statement, ensuring the bundle directory is created when it does not
exist.

// Step 3: Read package.json for version and metadata
const packageJson = JSON.parse(fs.readFileSync(path.join(PROJECT_ROOT, 'package.json'), 'utf8'));

// Step 4: Load and process manifest template
console.log('📝 Processing manifest template...');

const manifestTemplatePath = path.join(PROJECT_ROOT, 'manifest.template.json');
console.log(`📄 Using manifest: manifest.template.json`);

let manifestTemplate;
try {
manifestTemplate = fs.readFileSync(manifestTemplatePath, 'utf8');
} catch (error) {
console.error('❌ Failed to read manifest template:', manifestTemplatePath);
process.exit(1);
}

// Replace template variables
const manifestContent = manifestTemplate.replace('{{VERSION}}', packageJson.version);

// Parse and validate the resulting manifest
let manifest;
try {
manifest = JSON.parse(manifestContent);
} catch (error) {
console.error('❌ Invalid JSON in manifest template:', error.message);
process.exit(1);
}

// Write manifest
fs.writeFileSync(MANIFEST_PATH, JSON.stringify(manifest, null, 2));
console.log('✅ Created manifest.json');
// Step 5: Copy necessary files
const filesToCopy = [
'dist',
'package.json',
'README.md',
'LICENSE',
'PRIVACY.md',
'icon.png'
];

filesToCopy.forEach(file => {
const srcPath = path.join(PROJECT_ROOT, file);
const destPath = path.join(BUNDLE_DIR, file);

if (fs.existsSync(srcPath)) {
if (fs.statSync(srcPath).isDirectory()) {
// Copy directory recursively
fs.cpSync(srcPath, destPath, { recursive: true });
} else {
// Copy file
fs.copyFileSync(srcPath, destPath);
}
console.log(`✅ Copied ${file}`);
} else {
console.log(`⚠️ Skipped ${file} (not found)`);
}
});

// Step 6: Create package.json in bundle with production dependencies
const bundlePackageJson = {
name: manifest.name,
version: manifest.version,
description: manifest.description,
main: "dist/index.js",
author: manifest.author,
license: manifest.license,
repository: manifest.repository, dependencies: {
"@modelcontextprotocol/sdk": "^1.9.0",
"@vscode/ripgrep": "^1.15.9",
"cross-fetch": "^4.1.0",
"fastest-levenshtein": "^1.0.16",
"glob": "^10.3.10",
"isbinaryfile": "^5.0.4",
"zod": "^3.24.1",
"zod-to-json-schema": "^3.23.5"
}
};

fs.writeFileSync(
path.join(BUNDLE_DIR, 'package.json'),
JSON.stringify(bundlePackageJson, null, 2)
);

// Step 6b: Install dependencies in bundle directory
console.log('📦 Installing production dependencies in bundle...');
try {
execSync('npm install --omit=dev --production', { cwd: BUNDLE_DIR, stdio: 'inherit' });
console.log('✅ Dependencies installed');
} catch (error) {
console.error('❌ Failed to install dependencies:', error.message);
process.exit(1);
}

// Step 7: Validate manifest
console.log('🔍 Validating manifest...');
try {
execSync(`mcpb validate "${MANIFEST_PATH}"`, { stdio: 'inherit' });
console.log('✅ Manifest validation passed');
} catch (error) {
console.error('❌ Manifest validation failed:', error.message);
process.exit(1);
}
Comment on lines +137 to +142

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

🧩 Analysis chain

Verify mcpb CLI tool availability.

The script depends on the mcpb CLI tool for validation and packing but doesn't check if it's installed. This could cause runtime failures during the build process.


🏁 Script executed:

#!/bin/bash
# Description: Check if mcpb CLI tool is available and working

# Check if mcpb command exists
if command -v mcpb >/dev/null 2>&1; then
    echo "✅ mcpb CLI tool found"
    mcpb --version 2>/dev/null || echo "mcpb version command failed"
else
    echo "❌ mcpb CLI tool not found"
    echo "This tool is required for bundle validation and packing"
    echo "Install it with: npm install -g mcpb"
    exit 1
fi

Length of output: 118


Add availability check for mcpb CLI before execution.
scripts/build-mcpb.cjs:126-131
The script currently invokes mcpb without verifying it’s installed, leading to opaque failures. Insert a preflight check (e.g. command -v mcpb or spawnSync('mcpb',['--version'])) and emit a clear error with install instructions before calling mcpb validate.

🤖 Prompt for AI Agents
In scripts/build-mcpb.cjs around lines 126 to 131, the script calls `mcpb
validate` without checking that the `mcpb` CLI is installed; add a preflight
availability check (for example use child_process.spawnSync('mcpb',
['--version']) or run a shell `command -v mcpb`) prior to execSync, and if the
check fails log a clear error message that explains mcpb is not found and gives
install instructions (or a link) and exit with code 1; only proceed to
execSync(`mcpb validate ...`) when the check succeeds.

// Step 8: Pack the bundle
console.log('📦 Creating .mcpb bundle...');
const outputFile = path.join(PROJECT_ROOT, `${manifest.name}-${manifest.version}.mcpb`);

try {
execSync(`mcpb pack "${BUNDLE_DIR}" "${outputFile}"`, { stdio: 'inherit' });
console.log('✅ MCPB bundle created successfully!');
console.log(`📁 Bundle location: ${outputFile}`);
} catch (error) {
console.error('❌ Bundle creation failed:', error.message);
process.exit(1);
}

console.log('');
console.log('🎉 Desktop Commander MCPB bundle is ready!');
console.log('');
console.log('Next steps:');
console.log('1. Test the bundle by installing it in Claude Desktop:');
console.log(' Settings → Extensions → Advanced Settings → Install Extension');
console.log(`2. Select the file: ${outputFile}`);
console.log('3. Configure any settings and test the functionality');
console.log('');
console.log('To submit to Anthropic directory:');
console.log('- Ensure privacy policy is accessible at the GitHub URL');
console.log('- Complete destructive operation annotations (✅ Done)');
console.log('- Submit via Anthropic desktop extensions interest form');
Loading