Skip to main content
Glama
masamunet

npm-dev-mcp

by masamunet

auto_recover

Automatically recover npm-dev-mcp server by performing health checks, executing recovery steps, and verifying restoration.

Instructions

MCPサーバーの自動復旧を実行(ヘルスチェック→復旧→再検証)

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
maxRetriesNo最大復旧試行回数(デフォルト: 3)
forceRecoverNo強制復旧モード(デフォルト: false)
restartMcpNoMCPサーバー自体の再起動を含むか(デフォルト: false)

Implementation Reference

  • Main handler function for the auto_recover tool. Orchestrates multi-step recovery: health check, process recovery, state recovery, post-recovery verification with retries.
    export async function autoRecover(args: {
      maxRetries?: number;
      forceRecover?: boolean;
      restartMcp?: boolean;
    } = {}): Promise<string> {
      const logger = Logger.getInstance();
      const healthChecker = HealthChecker.getInstance();
      const processManager = ProcessManager.getInstance();
      const stateManager = StateManager.getInstance();
    
      const maxRetries = args.maxRetries || 3;
      const forceRecover = args.forceRecover || false;
      const restartMcp = args.restartMcp || false;
    
      let attempts = 0;
      const warnings: string[] = [];
      const steps = {
        healthCheck: false,
        processRecovery: false,
        stateRecovery: false,
        mcpRestart: false
      };
    
      try {
        logger.info('Starting auto recovery process', { maxRetries, forceRecover, restartMcp });
    
        while (attempts < maxRetries) {
          attempts++;
          logger.info(`Recovery attempt ${attempts}/${maxRetries}`);
    
          // Step 1: ヘルスチェック
          try {
            const healthStatus = await healthChecker.performHealthCheck();
            steps.healthCheck = true;
    
            if (healthStatus.isHealthy) {
              logger.info('System is healthy, no recovery needed');
              return JSON.stringify({
                success: true,
                message: 'システムは正常状態です。復旧は不要でした。',
                steps,
                attempts,
                finalHealth: healthStatus,
                warnings,
                timestamp: new Date().toISOString()
              } as AutoRecoveryResult);
            }
    
            logger.warn('System unhealthy, proceeding with recovery', {
              devServerStatus: healthStatus.devServerStatus,
              checks: healthStatus.checks
            });
    
          } catch (error) {
            logger.error('Health check failed', { error });
            warnings.push(`ヘルスチェック失敗: ${error}`);
          }
    
          // Step 2: プロセス復旧
          try {
            const activeProcesses = await processManager.getStatus();
            const noRunningProcesses = activeProcesses.every(p => p.status !== 'running');
    
            if (noRunningProcesses) {
              logger.info('Attempting process recovery');
    
              // 状態から復旧を試行
              const recoveryResult = await recoverFromState({ force: forceRecover });
              const result = JSON.parse(recoveryResult);
    
              if (result.success) {
                steps.processRecovery = true;
                logger.info('Process recovery successful');
              } else {
                warnings.push(`プロセス復旧失敗: ${result.message}`);
    
                // 復旧に失敗した場合は新しいプロセスを開始
                try {
                  // Start a default one if none exist? Or just skip?
                  // Maybe start in CWD as fallback
                  await processManager.startDevServer();
                  steps.processRecovery = true;
                  logger.info('Started new dev server process');
                } catch (startError) {
                  warnings.push(`新プロセス開始失敗: ${startError}`);
                }
              }
            } else {
              steps.processRecovery = true;
              logger.info('At least one process is already running');
            }
          } catch (error) {
            logger.error('Process recovery failed', { error });
            warnings.push(`プロセス復旧エラー: ${error}`);
          }
    
          // Step 3: 状態復旧
          try {
            await stateManager.ensureStateConsistency();
            steps.stateRecovery = true;
            logger.info('State recovery completed');
          } catch (error) {
            logger.error('State recovery failed', { error });
            warnings.push(`状態復旧エラー: ${error}`);
          }
    
          // Step 4: MCPサーバー再起動(要求された場合)
          if (restartMcp && attempts === maxRetries) {
            try {
              logger.warn('Attempting MCP server restart as last resort');
              // 注意: 実際のMCPサーバー再起動は外部プロセス管理が必要
              // PM2やsystemdなどでの管理が前提
              warnings.push('MCPサーバー再起動が要求されましたが、外部管理ツールでの実行が必要です');
              steps.mcpRestart = true;
            } catch (error) {
              logger.error('MCP restart failed', { error });
              warnings.push(`MCP再起動エラー: ${error}`);
            }
          }
    
          // 復旧後のヘルスチェック
          try {
            await new Promise(resolve => setTimeout(resolve, 2000)); // 2秒待機
            const postRecoveryHealth = await healthChecker.performHealthCheck();
    
            if (postRecoveryHealth.isHealthy) {
              logger.info('Recovery successful, system is now healthy');
              return JSON.stringify({
                success: true,
                message: `自動復旧が成功しました(${attempts}回目の試行)`,
                steps,
                attempts,
                finalHealth: postRecoveryHealth,
                warnings,
                timestamp: new Date().toISOString()
              } as AutoRecoveryResult);
            } else {
              logger.warn('System still unhealthy after recovery attempt', {
                attempt: attempts,
                devServerStatus: postRecoveryHealth.devServerStatus
              });
    
              if (attempts < maxRetries) {
                await new Promise(resolve => setTimeout(resolve, 5000)); // 5秒待機してリトライ
              }
            }
          } catch (error) {
            logger.error('Post-recovery health check failed', { error });
            warnings.push(`復旧後ヘルスチェック失敗: ${error}`);
          }
        }
    
        // 最大試行回数に達した場合
        logger.error('Auto recovery failed after maximum attempts', { attempts: maxRetries });
    
        return JSON.stringify({
          success: false,
          message: `自動復旧が失敗しました(${maxRetries}回試行)`,
          steps,
          attempts,
          warnings,
          timestamp: new Date().toISOString()
        } as AutoRecoveryResult);
    
      } catch (error) {
        logger.error('Auto recovery process failed', { error });
    
        return JSON.stringify({
          success: false,
          message: `自動復旧プロセスでエラーが発生しました: ${error}`,
          steps,
          attempts,
          warnings: [...warnings, String(error)],
          timestamp: new Date().toISOString()
        } as AutoRecoveryResult);
      }
    }
  • JSON Schema definition for the auto_recover tool inputs.
    export const autoRecoverSchema: Tool = {
      name: 'auto_recover',
      description: 'MCPサーバーの自動復旧を実行(ヘルスチェック→復旧→再検証)',
      inputSchema: {
        type: 'object',
        properties: {
          maxRetries: {
            type: 'number',
            description: '最大復旧試行回数(デフォルト: 3)',
            default: 3,
            minimum: 1,
            maximum: 10
          },
          forceRecover: {
            type: 'boolean',
            description: '強制復旧モード(デフォルト: false)',
            default: false
          },
          restartMcp: {
            type: 'boolean',
            description: 'MCPサーバー自体の再起動を含むか(デフォルト: false)',
            default: false
          }
        },
        additionalProperties: false
      }
  • src/index.ts:55-65 (registration)
    Registration of the auto_recover schema in the MCP server's tools list, used for listTools responses.
    const tools = [
      scanProjectDirsSchema,
      startDevServerSchema,
      getDevStatusSchema,
      getDevLogsSchema,
      stopDevServerSchema,
      restartDevServerSchema,
      getHealthStatusSchema,
      recoverFromStateSchema,
      autoRecoverSchema,
    ];
  • src/index.ts:207-215 (registration)
    Dispatch handler in MCP server CallToolRequest that invokes the autoRecover function.
    case 'auto_recover':
      return {
        content: [
          {
            type: 'text',
            text: await autoRecover(args as { maxRetries?: number; forceRecover?: boolean; restartMcp?: boolean }),
          },
        ],
      };
  • Dependency mapping for auto_recover tool, requiring stateManager and healthChecker services to be initialized.
    export const SERVICE_DEPENDENCIES = {
      'scan_project_dirs': ['projectContext'],
      'start_dev_server': ['stateManager'],
      'get_dev_status': ['stateManager'],
      'get_dev_logs': ['stateManager'],
      'stop_dev_server': ['stateManager'],
      'restart_dev_server': ['stateManager'],
      'get_health_status': ['healthChecker'],
      'recover_from_state': ['stateManager'],
      'auto_recover': ['stateManager', 'healthChecker']
    } as const;

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/masamunet/npm-dev-mcp'

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