-
-
Notifications
You must be signed in to change notification settings - Fork 738
Add tool annotations and new manifest and MCPB/DXT build script #246
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
989d866
be05b25
9754420
7994c13
91a5f85
c05d554
6d04b5f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,161 @@ | ||
| { | ||
| "$schema": "../../dist/mcpb-manifest.schema.json", | ||
| "manifest_version": "0.1", | ||
| "name": "desktop-commander", | ||
| "display_name": "Desktop Commander", | ||
| "version": "{{VERSION}}", | ||
| "description": "Build, explore, and automate on your local machine with access to files and terminal.", | ||
| "long_description": "Combine local filesystem access with full terminal control to handle technical tasks through natural language. Desktop Commander empowers you to build, explore, and automate - from organizing repositories to creating complete applications:\n* **Build from scratch** - Create features and applications with simple commands\n* **Manage development environments** - Set up servers, configure systems, and handle processes\n* **Manage context and documentation** - Keep track of project details and technical specifications\n* **Explore existing codebases and projects** - Navigate and understand complex repositories\n\nThis extension bridges technical skill gaps by providing full command-line superpowers through an interface that understands your intent and handles complexity automatically.", | ||
| "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://github.com/wonderwhy-er/DesktopCommanderMCP/issues", | ||
| "icon": "icon.png", | ||
| "server": { | ||
| "type": "node", | ||
| "entry_point": "dist/index.js", | ||
| "mcp_config": { | ||
| "command": "node", | ||
| "args": [ | ||
| "${__dirname}/dist/index.js" | ||
| ], | ||
| "env": { | ||
| "MCP_DXT": "true", | ||
| "NODE_ENV": "production" | ||
| } | ||
| } | ||
| }, | ||
| "tools": [ | ||
| { | ||
| "name": "get_config", | ||
| "description": "Get the complete server configuration including blocked commands, allowed directories, file limits, telemetry settings, client info, and system information." | ||
| }, | ||
| { | ||
| "name": "set_config_value", | ||
| "description": "Set a specific configuration value by key. WARNING: Should be used in a separate chat from file operations to prevent security issues." | ||
| }, | ||
| { | ||
| "name": "read_file", | ||
| "description": "Read the contents of a file from the file system or URL with optional offset and length parameters. Supports partial reading and handles images." | ||
| }, | ||
| { | ||
| "name": "read_multiple_files", | ||
| "description": "Read the contents of multiple files simultaneously. Handles text files and renders images." | ||
| }, | ||
| { | ||
| "name": "write_file", | ||
| "description": "Write or append to file contents. Always write files in chunks of 25-30 lines maximum for best performance." | ||
| }, | ||
| { | ||
| "name": "create_directory", | ||
| "description": "Create a new directory or ensure a directory exists. Can create multiple nested directories in one operation." | ||
| }, | ||
| { | ||
| "name": "list_directory", | ||
| "description": "Get a detailed listing of all files and directories in a specified path." | ||
| }, | ||
| { | ||
| "name": "move_file", | ||
| "description": "Move or rename files and directories between locations." | ||
| }, | ||
| { | ||
| "name": "start_search", | ||
| "description": "Start a streaming search for files by name or content within files. Returns results progressively with session ID." | ||
| }, | ||
| { | ||
| "name": "get_more_search_results", | ||
| "description": "Get more results from an active search with offset-based pagination." | ||
| }, | ||
| { | ||
| "name": "stop_search", | ||
| "description": "Stop an active search gracefully when you've found what you need." | ||
| }, | ||
| { | ||
| "name": "list_searches", | ||
| "description": "List all active searches with their status and runtime information." | ||
| }, | ||
| { | ||
| "name": "get_file_info", | ||
| "description": "Retrieve detailed metadata about a file or directory including size, timestamps, permissions, and line counts." | ||
| }, | ||
| { | ||
| "name": "edit_block", | ||
| "description": "Apply surgical text replacements to files. Make small, focused edits with minimal context for precision." | ||
| }, | ||
| { | ||
| "name": "start_process", | ||
| "description": "Start a new terminal process with intelligent state detection. Primary tool for local file analysis (CSV, JSON, logs, etc.)." | ||
| }, | ||
| { | ||
| "name": "read_process_output", | ||
| "description": "Read output from a running process with intelligent completion detection and REPL prompt recognition." | ||
| }, | ||
| { | ||
| "name": "interact_with_process", | ||
| "description": "Send input to a running process and automatically receive the response. Critical tool for all local file analysis." | ||
| }, | ||
| { | ||
| "name": "force_terminate", | ||
| "description": "Force terminate a running terminal session." | ||
| }, | ||
| { | ||
| "name": "list_sessions", | ||
| "description": "List all active terminal sessions with status information including blocked state and runtime." | ||
| }, | ||
| { | ||
| "name": "list_processes", | ||
| "description": "List all running processes with PID, command name, CPU usage, and memory usage." | ||
| }, | ||
| { | ||
| "name": "kill_process", | ||
| "description": "Terminate a running process by PID. Use with caution." | ||
| }, | ||
| { | ||
| "name": "get_usage_stats", | ||
| "description": "Get usage statistics for debugging and analysis including tool usage and performance metrics." | ||
| }, | ||
| { | ||
| "name": "give_feedback_to_desktop_commander", | ||
| "description": "Open feedback form in browser to provide feedback about Desktop Commander." | ||
| }, | ||
| { | ||
| "name": "get_prompts", | ||
| "description": "Browse and retrieve curated Desktop Commander prompts for various tasks and workflows." | ||
| } | ||
| ], | ||
| "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" | ||
| } | ||
| } | ||
| } | ||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| 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
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix bundle directory creation syntax error.
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
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||
| // 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
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion 🧩 Analysis chainVerify mcpb CLI tool availability. The script depends on the 🏁 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
fiLength of output: 118 Add availability check for mcpb CLI before execution. 🤖 Prompt for AI Agents |
||||||||||||||||
| // 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'); | ||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix the MCP command args path (literal
${__dirname}won’t resolve).mcp_config.argsis 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:
📝 Committable suggestion
🤖 Prompt for AI Agents