Skip to main content
Glama

hypertool-mcp

setup.tsโ€ข9.26 kB
/** * Global installation setup script * Installs Hypertool for all detected applications * Usage: npx -y @toolprint/hypertool-mcp --install */ import { promises as fs } from "fs"; import { join } from "path"; import { homedir } from "os"; import inquirer from "inquirer"; import { displayBanner, output } from "../../utils/output.js"; import { theme } from "../../utils/theme.js"; import { fileExists, hasClaudeCodeGlobalHypertoolSlashCommands, } from "../shared/mcpSetupUtils.js"; import { ClaudeDesktopSetup } from "../claude-desktop/setup.js"; import { CursorSetup } from "../cursor/setup.js"; import { ClaudeCodeSetup } from "../claude-code/setup.js"; import { createCommandTemplates } from "../claude-code/utils.js"; interface DetectedApp { name: string; displayName: string; configPath: string; setupClass: new () => { run: (dryRun: boolean) => Promise<void> }; } export class GlobalSetup { private dryRun: boolean = false; /** * Detect installed applications */ private async detectInstalledApps(): Promise<DetectedApp[]> { const apps: DetectedApp[] = []; // Check Claude Code first (if in a project directory) const currentDir = process.cwd(); const hasGit = await fileExists(join(currentDir, ".git")); const hasMcpJson = await fileExists(join(currentDir, ".mcp.json")); if (hasGit || hasMcpJson) { apps.push({ name: "claude-code", displayName: "๐Ÿค– Claude Code (current project)", configPath: join(currentDir, ".mcp.json"), setupClass: ClaudeCodeSetup, }); } // Check Claude Desktop (macOS) const claudeDesktopPath = join( homedir(), "Library/Application Support/Claude/claude_desktop_config.json" ); if (await fileExists(claudeDesktopPath)) { apps.push({ name: "claude-desktop", displayName: "๐Ÿ–ฅ๏ธ Claude Desktop", configPath: claudeDesktopPath, setupClass: ClaudeDesktopSetup, }); } // Check Cursor const cursorPath = join(homedir(), ".cursor/mcp.json"); if (await fileExists(cursorPath)) { apps.push({ name: "cursor", displayName: "โœ๏ธ Cursor", configPath: cursorPath, setupClass: CursorSetup, }); } return apps; } async run(dryRun: boolean = false): Promise<void> { this.dryRun = dryRun; try { // Clear terminal at the beginning output.clearTerminal(); displayBanner(); // Welcome banner output.displayHeader("๐Ÿš€ Hypertool Global Installation"); if (this.dryRun) { output.info(theme.info("๐Ÿ” [DRY RUN MODE] - No changes will be made")); output.displaySpaceBuffer(1); } // Step 1: Detect installed applications const detectedApps: DetectedApp[] = await this.detectInstalledApps(); if (detectedApps.length === 0) { output.warn("โš ๏ธ No supported applications detected"); output.displaySpaceBuffer(1); output.displaySubHeader("Supported applications:"); output.displayInstruction("โ€ข Claude Code (in project directory)"); output.displayInstruction("โ€ข Claude Desktop (macOS)"); output.displayInstruction("โ€ข Cursor IDE"); output.displaySpaceBuffer(1); output.info( "๐Ÿ’ก Install one of these applications and run the installer again" ); return; } // Step 2: Show detected applications output.displaySubHeader("๐Ÿ” Detected Applications:"); output.displaySpaceBuffer(1); detectedApps.forEach((app) => { output.info(`โœ… ${app.displayName}`); output.displayInstruction(` Config: ${app.configPath}`); }); output.displaySpaceBuffer(1); // Step 3: Check for global slash commands const hasGlobalCommands = await hasClaudeCodeGlobalHypertoolSlashCommands(); let shouldInstallGlobalCommands = false; if (hasGlobalCommands) { output.info( "โœ… Global CC slash commands already installed in ~/.claude/commands/ht/" ); output.displaySpaceBuffer(1); } else { output.warn("โš ๏ธ Global slash commands not found"); output.displaySpaceBuffer(1); const { installCommands } = await inquirer.prompt([ { type: "confirm", name: "installCommands", message: theme.warning( "Install global slash commands? (recommended)" ), default: true, }, ]); shouldInstallGlobalCommands = installCommands; output.displaySpaceBuffer(1); } // Step 4: Get user confirmation const { shouldProceed } = await inquirer.prompt([ { type: "confirm", name: "shouldProceed", message: theme.warning( `Install Hypertool for ${detectedApps.length} application(s)?` ), default: true, }, ]); if (!shouldProceed) { output.info("Installation cancelled."); return; } output.displaySpaceBuffer(1); // Step 5: Install global slash commands if needed if (shouldInstallGlobalCommands) { if (this.dryRun) { output.info( "[DRY RUN] Would install global slash commands to: ~/.claude/commands/ht/" ); } else { output.info("๐Ÿ“ฆ Installing global slash commands..."); const globalCommandsDir = join(homedir(), ".claude/commands/ht"); // Clean existing commands and install fresh ones try { await fs.rm(globalCommandsDir, { recursive: true, force: true }); } catch { // Directory doesn't exist, continue } // Create directory await fs.mkdir(globalCommandsDir, { recursive: true }); // Generate command templates const commandTemplates = await createCommandTemplates(); // Write all command files for (const [filename, content] of Object.entries(commandTemplates)) { const filePath = join(globalCommandsDir, filename); await fs.writeFile(filePath, content, "utf8"); } output.displaySpaceBuffer(1); } } // Step 6: Run individual setup scripts const results: { app: string; success: boolean; error?: string }[] = []; for (const app of detectedApps) { // Add separator between apps output.displaySeparator(); output.displaySpaceBuffer(1); // // Display app header with typewriter effect // const headerEmoji = app.name === 'claude-code' ? '๐Ÿ“' : // app.name === 'claude-desktop' ? '๐Ÿ–ฅ๏ธ' : // app.name === 'cursor' ? 'โœ๏ธ' : '๐Ÿ“ฆ'; // const headerText = `${headerEmoji} ${app.displayName}`; if (this.dryRun) { await output.displayHeader(`[DRY RUN] ${app.displayName}`); } else { await output.displayHeader(app.displayName); } output.displaySpaceBuffer(1); try { const setup = new app.setupClass(); await setup.run(this.dryRun); results.push({ app: app.displayName, success: true }); } catch (error) { results.push({ app: app.displayName, success: false, error: error instanceof Error ? error.message : String(error), }); } } // Success summary output.displaySpaceBuffer(1); output.displaySeparator(); output.displaySpaceBuffer(1); if (this.dryRun) { output.info( theme.warning("๐Ÿ” [DRY RUN] Installation simulation complete") ); output.displaySpaceBuffer(1); output.info("No actual changes were made to your system."); } else { output.success("โœจ All installations complete!"); output.displaySpaceBuffer(1); // Show concise results const successfulApps = results.filter((r) => r.success).length; const failedApps = results.filter((r) => !r.success).length; if (successfulApps > 0) { output.success( `โœ… Configured ${successfulApps} application(s) successfully` ); } if (failedApps > 0) { output.error(`โŒ Failed to configure ${failedApps} application(s)`); } if (shouldInstallGlobalCommands) { output.success("โœ… Installed global slash commands"); } output.displaySpaceBuffer(1); // Simple next step if (successfulApps > 0) { output.info("๐ŸŽฏ Restart your applications to use Hypertool!"); output.displaySpaceBuffer(1); } } } catch (error) { output.error("โŒ Setup failed:"); output.error(error instanceof Error ? error.message : String(error)); process.exit(1); } } } // Run the setup if this script is executed directly if (import.meta.url === `file://${process.argv[1]}`) { const setup = new GlobalSetup(); setup.run().catch((error) => { output.error("Setup failed:"); output.error(error instanceof Error ? error.message : String(error)); process.exit(1); }); }

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/toolprint/hypertool-mcp'

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