Skip to main content
Glama
process-manager.ts5.49 kB
import treeKill from 'tree-kill'; import { ProcessDetector, MCPProcess } from './process-detector.js'; import { exec } from 'child_process'; import { promisify } from 'util'; import { platform } from 'os'; const execAsync = promisify(exec); export interface RestartResult { success: boolean; message: string; oldPid?: number; newPid?: number; error?: string; } export class ProcessManager { private detector = new ProcessDetector(); private platform = platform(); async restartMCPHandler(): Promise<RestartResult> { try { // Step 1: Find the MCP handler process const mcpProcess = await this.detector.findMCPHandlerProcess(); if (!mcpProcess) { return { success: false, message: 'Could not find MCP handler process. It may not be running.', error: 'MCP_HANDLER_NOT_FOUND' }; } const oldPid = mcpProcess.pid; console.log(`Found MCP handler process: PID ${oldPid}`); // Step 2: Gracefully terminate the process await this.gracefulKill(mcpProcess.pid); // Step 3: Wait a moment for Claude Desktop to detect the disconnection await this.delay(1000); // Step 4: Verify the process was terminated const stillRunning = await this.isProcessRunning(oldPid); if (stillRunning) { // Force kill if graceful didn't work await this.forceKill(oldPid); await this.delay(500); } // Step 5: Wait for Claude Desktop to restart the MCP handler const newProcess = await this.waitForMCPHandler(5000); if (newProcess) { return { success: true, message: 'MCP handler restarted successfully', oldPid, newPid: newProcess.pid }; } else { return { success: false, message: 'MCP handler was terminated but did not restart automatically', oldPid, error: 'MCP_HANDLER_NOT_RESTARTED' }; } } catch (error) { return { success: false, message: 'Failed to restart MCP handler', error: error instanceof Error ? error.message : 'UNKNOWN_ERROR' }; } } async restartClaudeDesktop(): Promise<RestartResult> { try { const claudeProcess = await this.detector.findClaudeDesktopProcess(); if (!claudeProcess) { return { success: false, message: 'Claude Desktop is not running', error: 'CLAUDE_NOT_RUNNING' }; } const oldPid = claudeProcess.pid; // Kill Claude Desktop await this.gracefulKill(claudeProcess.pid); await this.delay(2000); // Restart Claude Desktop based on platform await this.launchClaudeDesktop(); // Wait for it to start const newProcess = await this.waitForClaudeDesktop(10000); if (newProcess) { return { success: true, message: 'Claude Desktop restarted successfully', oldPid, newPid: newProcess.pid }; } else { return { success: false, message: 'Failed to restart Claude Desktop', error: 'CLAUDE_RESTART_FAILED' }; } } catch (error) { return { success: false, message: 'Error restarting Claude Desktop', error: error instanceof Error ? error.message : 'UNKNOWN_ERROR' }; } } private async gracefulKill(pid: number): Promise<void> { return new Promise((resolve, reject) => { treeKill(pid, 'SIGTERM', (err: Error | undefined) => { if (err && err.message !== 'No such process') { reject(err); } else { resolve(); } }); }); } private async forceKill(pid: number): Promise<void> { return new Promise((resolve, reject) => { treeKill(pid, 'SIGKILL', (err: Error | undefined) => { if (err && err.message !== 'No such process') { reject(err); } else { resolve(); } }); }); } private async isProcessRunning(pid: number): Promise<boolean> { try { process.kill(pid, 0); return true; } catch { return false; } } private async waitForMCPHandler(timeout: number): Promise<MCPProcess | null> { const startTime = Date.now(); while (Date.now() - startTime < timeout) { const process = await this.detector.findMCPHandlerProcess(); if (process) { return process; } await this.delay(500); } return null; } private async waitForClaudeDesktop(timeout: number): Promise<MCPProcess | null> { const startTime = Date.now(); while (Date.now() - startTime < timeout) { const process = await this.detector.findClaudeDesktopProcess(); if (process) { return process; } await this.delay(500); } return null; } private async launchClaudeDesktop(): Promise<void> { switch (this.platform) { case 'darwin': await execAsync('open -a "Claude"'); break; case 'win32': await execAsync('start "" "Claude.exe"'); break; case 'linux': await execAsync('claude-desktop &'); break; default: throw new Error(`Unsupported platform: ${this.platform}`); } } private delay(ms: number): Promise<void> { return new Promise(resolve => setTimeout(resolve, ms)); } }

Implementation Reference

Latest Blog Posts

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/199-mcp/mcp-autostarter'

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