Skip to main content
Glama

Claude Desktop Commander MCP

build-mcpb.cjs5.57 kB
#!/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 }); // 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); } // 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');

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/wonderwhy-er/DesktopCommanderMCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server