Skip to main content
Glama

hypertool-mcp

migrator.tsโ€ข4.85 kB
/** * Migration logic for existing HyperTool installations */ import { promises as fs } from "fs"; import { join } from "path"; import { homedir } from "os"; import { ConfigurationManager } from "../index.js"; import { MCPConfig } from "../types/index.js"; import { createChildLogger } from "../../utils/logging.js"; const logger = createChildLogger({ module: "ConfigMigrator" }); export class ConfigMigrator { private configManager: ConfigurationManager; constructor() { this.configManager = new ConfigurationManager(); } /** * Check if this is a legacy installation that needs migration */ async needsMigration(): Promise<boolean> { // Check for legacy configurations in application-specific locations const legacyPaths = [ join(homedir(), "Library/Application Support/Claude/mcp.hypertool.json"), join(homedir(), ".cursor/mcp.hypertool.json"), join(process.cwd(), "mcp.hypertool.json"), ]; for (const path of legacyPaths) { try { await fs.access(path); return true; // Found at least one legacy config } catch { // Continue checking } } // Check if new config exists const newConfigPath = join(homedir(), ".toolprint/hypertool-mcp/mcp.json"); try { await fs.access(newConfigPath); return false; // Already migrated } catch { // No new config yet } return false; } /** * Migrate from legacy per-application configs to centralized config */ async migrate(): Promise<{ migrated: string[]; failed: string[]; }> { await this.configManager.initialize(); const migrated: string[] = []; const failed: string[] = []; const mergedServers: MCPConfig = { mcpServers: {} }; // Migrate Claude Desktop try { const claudeConfig = await this.migrateLegacyConfig( join(homedir(), "Library/Application Support/Claude/mcp.hypertool.json") ); if (claudeConfig) { Object.assign(mergedServers.mcpServers, claudeConfig.mcpServers); migrated.push("claude-desktop"); } } catch (error) { logger.warn("Failed to migrate Claude Desktop config", { error }); failed.push("claude-desktop"); } // Migrate Cursor try { const cursorConfig = await this.migrateLegacyConfig( join(homedir(), ".cursor/mcp.hypertool.json") ); if (cursorConfig) { Object.assign(mergedServers.mcpServers, cursorConfig.mcpServers); migrated.push("cursor"); } } catch (error) { logger.warn("Failed to migrate Cursor config", { error }); failed.push("cursor"); } // Migrate Claude Code (project-local) try { const claudeCodeConfig = await this.migrateLegacyConfig( join(process.cwd(), "mcp.hypertool.json") ); if (claudeCodeConfig) { Object.assign(mergedServers.mcpServers, claudeCodeConfig.mcpServers); migrated.push("claude-code"); } } catch { // Project-local configs might not exist, which is fine } // Save merged configuration if we migrated anything if (migrated.length > 0) { const configPath = join(homedir(), ".toolprint/hypertool-mcp/mcp.json"); // Add metadata mergedServers._metadata = { sources: {} }; for (const [serverName] of Object.entries(mergedServers.mcpServers)) { // Try to guess which app each server came from based on the order const sourceApp = migrated[0]; // Simple heuristic mergedServers._metadata.sources![serverName] = { app: sourceApp, importedAt: new Date().toISOString(), }; } await fs.writeFile( configPath, JSON.stringify(mergedServers, null, 2), "utf-8" ); } return { migrated, failed }; } /** * Migrate a single legacy configuration file */ private async migrateLegacyConfig( legacyPath: string ): Promise<MCPConfig | null> { try { const content = await fs.readFile(legacyPath, "utf-8"); const config = JSON.parse(content); // Legacy configs already use standard format return { mcpServers: config.mcpServers || {}, }; } catch { return null; } } /** * Clean up legacy configuration files after successful migration */ async cleanupLegacyConfigs(): Promise<void> { const legacyPaths = [ join(homedir(), "Library/Application Support/Claude/mcp.hypertool.json"), join(homedir(), ".cursor/mcp.hypertool.json"), join(process.cwd(), "mcp.hypertool.json"), ]; for (const path of legacyPaths) { try { await fs.unlink(path); logger.info(`Removed legacy config: ${path}`, { path }); } catch { // File doesn't exist or can't be removed, ignore } } } }

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