Skip to content

Commit ba3f6d7

Browse files
committed
Add the install-mcp command
1 parent 7312483 commit ba3f6d7

File tree

10 files changed

+796
-25
lines changed

10 files changed

+796
-25
lines changed

packages/cli-v3/install-mcp.sh

Lines changed: 258 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,20 +12,26 @@ show_help() {
1212
echo "Usage: $0 [OPTIONS]"
1313
echo ""
1414
echo "Options:"
15-
echo " -t, --target TARGET Install target: claude, cursor, vscode, or all (default: all)"
15+
echo " -t, --target TARGET Install target: claude, claude-desktop, cursor, vscode, crush, windsurf, or all (default: all)"
1616
echo " -h, --help Show this help message"
1717
echo ""
1818
echo "Targets:"
19-
echo " claude Install for Claude Code (~/.claude.json)"
20-
echo " cursor Install for Cursor (~/.cursor/mcp.json)"
21-
echo " vscode Install for VS Code (~/Library/Application Support/Code/User/mcp.json)"
22-
echo " all Install for all supported targets"
19+
echo " claude Install for Claude Code (~/.claude.json)"
20+
echo " claude-desktop Install for Claude Desktop (~/Library/Application Support/Claude/claude_desktop_config.json)"
21+
echo " cursor Install for Cursor (~/.cursor/mcp.json)"
22+
echo " vscode Install for VS Code (~/Library/Application Support/Code/User/mcp.json)"
23+
echo " crush Install for Crush (~/.config/crush/crush.json)"
24+
echo " windsurf Install for Windsurf (~/.codeium/windsurf/mcp_config.json)"
25+
echo " all Install for all supported targets"
2326
echo ""
2427
echo "Examples:"
25-
echo " $0 # Install for all targets"
26-
echo " $0 -t claude # Install only for Claude Code"
27-
echo " $0 -t cursor # Install only for Cursor"
28-
echo " $0 -t vscode # Install only for VS Code"
28+
echo " $0 # Install for all targets"
29+
echo " $0 -t claude # Install only for Claude Code"
30+
echo " $0 -t claude-desktop # Install only for Claude Desktop"
31+
echo " $0 -t cursor # Install only for Cursor"
32+
echo " $0 -t vscode # Install only for VS Code"
33+
echo " $0 -t crush # Install only for Crush"
34+
echo " $0 -t windsurf # Install only for Windsurf"
2935
}
3036

3137
# Parse arguments
@@ -49,11 +55,11 @@ done
4955

5056
# Validate target
5157
case $TARGET in
52-
claude|cursor|vscode|all)
58+
claude|claude-desktop|cursor|vscode|crush|windsurf|all)
5359
;;
5460
*)
5561
echo "❌ Invalid target: $TARGET"
56-
echo "Valid targets are: claude, cursor, vscode, all"
62+
echo "Valid targets are: claude, claude-desktop, cursor, vscode, crush, windsurf, all"
5763
exit 1
5864
;;
5965
esac
@@ -160,6 +166,81 @@ install_claude() {
160166
"
161167
}
162168

169+
# Function to install for Claude Desktop
170+
install_claude_desktop() {
171+
echo ""
172+
echo "🔧 Installing for Claude Desktop..."
173+
174+
local CLAUDE_DESKTOP_DIR="$HOME/Library/Application Support/Claude"
175+
local CLAUDE_DESKTOP_CONFIG="$CLAUDE_DESKTOP_DIR/claude_desktop_config.json"
176+
177+
echo "📁 Claude Desktop configuration file: $CLAUDE_DESKTOP_CONFIG"
178+
179+
# Create Claude Desktop directory if it doesn't exist
180+
if [ ! -d "$CLAUDE_DESKTOP_DIR" ]; then
181+
echo "📝 Creating Claude Desktop configuration directory..."
182+
mkdir -p "$CLAUDE_DESKTOP_DIR"
183+
fi
184+
185+
# Check if Claude Desktop config exists, create if it doesn't
186+
if [ ! -f "$CLAUDE_DESKTOP_CONFIG" ]; then
187+
echo "📝 Creating new Claude Desktop configuration file..."
188+
echo '{"mcpServers": {}}' > "$CLAUDE_DESKTOP_CONFIG"
189+
fi
190+
191+
# Use Node.js to manipulate the JSON
192+
echo "🔧 Updating Claude Desktop configuration..."
193+
194+
node -e "
195+
const fs = require('fs');
196+
const path = require('path');
197+
198+
const configPath = '$CLAUDE_DESKTOP_CONFIG';
199+
const nodePath = '$NODE_PATH';
200+
const cliPath = '$CLI_PATH';
201+
const logFile = '$MCP_LOG_FILE';
202+
203+
try {
204+
// Read existing config
205+
let config;
206+
try {
207+
const configContent = fs.readFileSync(configPath, 'utf8');
208+
config = JSON.parse(configContent);
209+
} catch (error) {
210+
console.log('📝 Creating new configuration structure...');
211+
config = {};
212+
}
213+
214+
// Ensure mcpServers object exists
215+
if (!config.mcpServers) {
216+
config.mcpServers = {};
217+
}
218+
219+
// Add/update trigger.dev entry
220+
config.mcpServers['trigger'] = {
221+
command: nodePath,
222+
args: [cliPath, 'mcp', '--log-file', logFile, '--api-url', 'http://localhost:3030']
223+
};
224+
225+
// Write back to file with proper formatting
226+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
227+
228+
console.log('✅ Successfully installed Trigger.dev MCP server to Claude Desktop');
229+
console.log('');
230+
console.log('📋 Claude Desktop Configuration:');
231+
console.log(' • Config file:', configPath);
232+
console.log(' • Node.js path:', nodePath);
233+
console.log(' • CLI path:', cliPath);
234+
console.log('');
235+
console.log('💡 You can now use Trigger.dev MCP commands in Claude Desktop.');
236+
237+
} catch (error) {
238+
console.error('❌ Error updating Claude Desktop configuration:', error.message);
239+
process.exit(1);
240+
}
241+
"
242+
}
243+
163244
# Function to install for Cursor
164245
install_cursor() {
165246
echo ""
@@ -310,21 +391,187 @@ install_vscode() {
310391
"
311392
}
312393

394+
# Function to install for Crush
395+
install_crush() {
396+
echo ""
397+
echo "🔧 Installing for Crush..."
398+
399+
local CRUSH_DIR="$HOME/.config/crush"
400+
local CRUSH_CONFIG="$CRUSH_DIR/crush.json"
401+
402+
echo "📁 Crush configuration file: $CRUSH_CONFIG"
403+
404+
# Create Crush config directory if it doesn't exist
405+
if [ ! -d "$CRUSH_DIR" ]; then
406+
echo "📝 Creating Crush configuration directory..."
407+
mkdir -p "$CRUSH_DIR"
408+
fi
409+
410+
# Check if Crush config exists, create if it doesn't
411+
if [ ! -f "$CRUSH_CONFIG" ]; then
412+
echo "📝 Creating new Crush configuration file..."
413+
echo '{"$schema": "https://charm.land/crush.json", "mcp": {}}' > "$CRUSH_CONFIG"
414+
fi
415+
416+
# Use Node.js to manipulate the JSON
417+
echo "🔧 Updating Crush configuration..."
418+
419+
node -e "
420+
const fs = require('fs');
421+
const path = require('path');
422+
423+
const configPath = '$CRUSH_CONFIG';
424+
const nodePath = '$NODE_PATH';
425+
const cliPath = '$CLI_PATH';
426+
const logFile = '$MCP_LOG_FILE';
427+
428+
try {
429+
// Read existing config
430+
let config;
431+
try {
432+
const configContent = fs.readFileSync(configPath, 'utf8');
433+
config = JSON.parse(configContent);
434+
} catch (error) {
435+
console.log('📝 Creating new configuration structure...');
436+
config = {};
437+
}
438+
439+
// Ensure schema and mcp object exists
440+
if (!config['\$schema']) {
441+
config['\$schema'] = 'https://charm.land/crush.json';
442+
}
443+
if (!config.mcp) {
444+
config.mcp = {};
445+
}
446+
447+
// Add/update trigger.dev entry
448+
config.mcp['trigger'] = {
449+
type: 'stdio',
450+
command: nodePath,
451+
args: [cliPath, 'mcp', '--log-file', logFile, '--api-url', 'http://localhost:3030']
452+
};
453+
454+
// Write back to file with proper formatting
455+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
456+
457+
console.log('✅ Successfully installed Trigger.dev MCP server to Crush');
458+
console.log('');
459+
console.log('📋 Crush Configuration:');
460+
console.log(' • Config file:', configPath);
461+
console.log(' • Node.js path:', nodePath);
462+
console.log(' • CLI path:', cliPath);
463+
console.log('');
464+
console.log('💡 You can now use Trigger.dev MCP commands in Crush.');
465+
466+
} catch (error) {
467+
console.error('❌ Error updating Crush configuration:', error.message);
468+
process.exit(1);
469+
}
470+
"
471+
}
472+
473+
# Function to install for Windsurf
474+
install_windsurf() {
475+
echo ""
476+
echo "🔧 Installing for Windsurf..."
477+
478+
local WINDSURF_DIR="$HOME/.codeium/windsurf"
479+
local WINDSURF_CONFIG="$WINDSURF_DIR/mcp_config.json"
480+
481+
echo "📁 Windsurf configuration file: $WINDSURF_CONFIG"
482+
483+
# Create Windsurf config directory if it doesn't exist
484+
if [ ! -d "$WINDSURF_DIR" ]; then
485+
echo "📝 Creating Windsurf configuration directory..."
486+
mkdir -p "$WINDSURF_DIR"
487+
fi
488+
489+
# Check if Windsurf config exists, create if it doesn't
490+
if [ ! -f "$WINDSURF_CONFIG" ]; then
491+
echo "📝 Creating new Windsurf configuration file..."
492+
echo '{"mcpServers": {}}' > "$WINDSURF_CONFIG"
493+
fi
494+
495+
# Use Node.js to manipulate the JSON
496+
echo "🔧 Updating Windsurf configuration..."
497+
498+
node -e "
499+
const fs = require('fs');
500+
const path = require('path');
501+
502+
const configPath = '$WINDSURF_CONFIG';
503+
const nodePath = '$NODE_PATH';
504+
const cliPath = '$CLI_PATH';
505+
const logFile = '$MCP_LOG_FILE';
506+
507+
try {
508+
// Read existing config
509+
let config;
510+
try {
511+
const configContent = fs.readFileSync(configPath, 'utf8');
512+
config = JSON.parse(configContent);
513+
} catch (error) {
514+
console.log('📝 Creating new configuration structure...');
515+
config = {};
516+
}
517+
518+
// Ensure mcpServers object exists
519+
if (!config.mcpServers) {
520+
config.mcpServers = {};
521+
}
522+
523+
// Add/update trigger.dev entry
524+
config.mcpServers['trigger'] = {
525+
command: nodePath,
526+
args: [cliPath, 'mcp', '--log-file', logFile, '--api-url', 'http://localhost:3030']
527+
};
528+
529+
// Write back to file with proper formatting
530+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
531+
532+
console.log('✅ Successfully installed Trigger.dev MCP server to Windsurf');
533+
console.log('');
534+
console.log('📋 Windsurf Configuration:');
535+
console.log(' • Config file:', configPath);
536+
console.log(' • Node.js path:', nodePath);
537+
console.log(' • CLI path:', cliPath);
538+
console.log('');
539+
console.log('💡 You can now use Trigger.dev MCP commands in Windsurf.');
540+
541+
} catch (error) {
542+
console.error('❌ Error updating Windsurf configuration:', error.message);
543+
process.exit(1);
544+
}
545+
"
546+
}
547+
313548
# Install based on target
314549
case $TARGET in
315550
claude)
316551
install_claude
317552
;;
553+
claude-desktop)
554+
install_claude_desktop
555+
;;
318556
cursor)
319557
install_cursor
320558
;;
321559
vscode)
322560
install_vscode
323561
;;
562+
crush)
563+
install_crush
564+
;;
565+
windsurf)
566+
install_windsurf
567+
;;
324568
all)
325569
install_claude
570+
install_claude_desktop
326571
install_cursor
327572
install_vscode
573+
install_crush
574+
install_windsurf
328575
;;
329576
esac
330577

packages/cli-v3/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@
8080
"inspector": "npx @modelcontextprotocol/inspector dist/esm/index.js mcp --log-file .mcp.log --api-url http://localhost:3030"
8181
},
8282
"dependencies": {
83-
"@clack/prompts": "^0.10.0",
83+
"@clack/prompts": "0.11.0",
8484
"@depot/cli": "0.0.1-cli.2.80.0",
8585
"@modelcontextprotocol/sdk": "^1.17.0",
8686
"@opentelemetry/api": "1.9.0",

packages/cli-v3/src/cli/common.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ export async function wrapCommandAction<T extends z.AnyZodObject, TResult>(
6868
if (e instanceof SkipLoggingError) {
6969
// do nothing
7070
} else if (e instanceof OutroCommandError) {
71-
outro("Operation cancelled");
71+
outro(e.message ?? "Operation cancelled");
7272
} else if (e instanceof SkipCommandError) {
7373
// do nothing
7474
} else if (e instanceof BundleError) {

packages/cli-v3/src/cli/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { configureMcpCommand } from "../commands/mcp.js";
1515
import { COMMAND_NAME } from "../consts.js";
1616
import { VERSION } from "../version.js";
1717
import { installExitHandler } from "./common.js";
18+
import { configureInstallMcpCommand } from "../commands/install-mcp.js";
1819

1920
export const program = new Command();
2021

@@ -36,5 +37,6 @@ configureUpdateCommand(program);
3637
configurePreviewCommand(program);
3738
configureAnalyzeCommand(program);
3839
configureMcpCommand(program);
40+
configureInstallMcpCommand(program);
3941

4042
installExitHandler();

0 commit comments

Comments
 (0)