Skip to main content
Glama
masamunet

npm-dev-mcp

by masamunet

recover_from_state

Restores npm development processes from saved state to resume interrupted work. Use this tool to recover background processes and continue development tasks.

Instructions

保存された状態から復旧を試行

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
forceNo強制的に復旧を実行するかどうか(デフォルト: false)

Implementation Reference

  • Main handler function for the 'recover_from_state' tool. Performs recovery of dev processes and project context from saved state using StateManager and ProcessManager. Supports force recovery.
    export async function recoverFromState(args: { force?: boolean } = {}): Promise<string> {
      const logger = Logger.getInstance();
      const stateManager = StateManager.getInstance();
      const processManager = ProcessManager.getInstance();
    
      try {
        logger.info('Starting recovery from saved state', { force: args.force });
    
        // 復旧情報を取得
        const recoveryInfo = await stateManager.getRecoveryInfo();
    
        if (!recoveryInfo.canRecover && !args.force) {
          return JSON.stringify({
            success: false,
            message: '復旧可能な状態が見つかりません。force=trueで強制実行できます。',
            recoveryInfo: {
              canRecover: false,
              hasDevProcess: !!recoveryInfo.devProcesses && recoveryInfo.devProcesses.length > 0,
              lastHealthy: recoveryInfo.lastHealthy,
              consecutiveFailures: recoveryInfo.consecutiveFailures
            }
          });
        }
    
        let recoveryResults = {
          devProcessRecovered: false,
          projectContextRecovered: false,
          warnings: [] as string[]
        };
    
        // 開発サーバープロセスの復旧を試行
        if (recoveryInfo.devProcesses && recoveryInfo.devProcesses.length > 0) {
          try {
            for (const proc of recoveryInfo.devProcesses) {
              logger.info('Attempting to recover dev process', {
                pid: proc.pid,
                directory: proc.directory
              });
    
              // 既存のプロセスが動作中かチェック
              const existingProcess = processManager.getProcess(proc.directory);
              if (existingProcess && existingProcess.status === 'running') {
                recoveryResults.warnings.push(`開発サーバー(${proc.directory})は既に動作中です`);
              } else {
                // プロセスが存在するかチェック
                const isProcessAlive = await checkProcessExists(proc.pid);
    
                if (isProcessAlive) {
                  // プロセスが生きている場合は、ProcessManagerに状態を復元(restartDevServer logic or equivalent)
                  // New ProcessManager.ts implementation handles restoration in constructor, 
                  // but checking here confirms if they are tracked.
                  if (!processManager.getProcess(proc.directory)) {
                    // If process exists but not in manager, it might be tricky without restart
                    recoveryResults.warnings.push(`PID ${proc.pid} (${proc.directory}) は生存していますが、MCP管理下に戻すには再起動が必要です`);
                  } else {
                    logger.info('Found existing process, already restored by ProcessManager');
                  }
                } else {
                  // プロセスが死んでいる場合は新しく開始
                  logger.info('Dead process detected, starting new dev server', { directory: proc.directory });
    
                  try {
                    const newProcess = await processManager.startDevServer(
                      proc.directory
                    );
    
                    if (newProcess.status === 'running') {
                      recoveryResults.devProcessRecovered = true;
                      logger.info('Dev server restarted successfully', {
                        newPid: newProcess.pid,
                        directory: newProcess.directory
                      });
                    }
                  } catch (startError) {
                    logger.error(`Failed to restart dev server for ${proc.directory}`, { error: startError });
                    recoveryResults.warnings.push(`${proc.directory} の再起動に失敗: ${startError}`);
                  }
                }
              }
            }
    
          } catch (error) {
            logger.error('Failed to recover dev processes', { error });
            recoveryResults.warnings.push(`開発サーバーの復旧に失敗: ${error}`);
          }
        }
    
        // プロジェクトコンテキストの復旧
        if (recoveryInfo.projectContext) {
          try {
            logger.info('Recovering project context', {
              currentDirectory: recoveryInfo.projectContext.currentDirectory,
              projectCount: recoveryInfo.projectContext.detectedProjects.length
            });
    
            // ProjectContextManagerに状態を復元
            // 注意: 実際の復元はProjectContextManagerの実装に依存
            recoveryResults.projectContextRecovered = true;
    
          } catch (error) {
            logger.error('Failed to recover project context', { error });
            recoveryResults.warnings.push(`プロジェクトコンテキストの復旧に失敗: ${error}`);
          }
        }
    
        // 復旧成功の場合は、現在の状態を保存
        // state saving happens automatically in ProcessManager actions
    
        const message = recoveryResults.devProcessRecovered || recoveryResults.projectContextRecovered
          ? '状態の復旧が完了しました'
          : '復旧可能な項目が見つかりませんでした';
    
        logger.info('Recovery completed', { recoveryResults });
    
        return JSON.stringify({
          success: true,
          message,
          recovery: {
            devProcessRecovered: recoveryResults.devProcessRecovered,
            projectContextRecovered: recoveryResults.projectContextRecovered,
            warnings: recoveryResults.warnings,
            previousProcesses: recoveryInfo.devProcesses,
            recoveryTimestamp: new Date().toISOString()
          }
        });
    
      } catch (error) {
        logger.error('Recovery failed', { error });
    
        return JSON.stringify({
          success: false,
          message: `復旧処理に失敗しました: ${error}`,
          error: String(error)
        });
      }
    }
  • Schema definition for the 'recover_from_state' tool, including input schema with optional 'force' boolean parameter.
    export const recoverFromStateSchema: Tool = {
      name: 'recover_from_state',
      description: '保存された状態から復旧を試行',
      inputSchema: {
        type: 'object',
        properties: {
          force: {
            type: 'boolean',
            description: '強制的に復旧を実行するかどうか(デフォルト: false)',
            default: false
          }
        },
        additionalProperties: false
      }
    };
  • src/index.ts:197-205 (registration)
    Registration and dispatching of the 'recover_from_state' tool in the main MCP server request handler switch statement.
    case 'recover_from_state':
      return {
        content: [
          {
            type: 'text',
            text: await recoverFromState(args as { force?: boolean }),
          },
        ],
      };
  • src/index.ts:55-65 (registration)
    Inclusion of recoverFromStateSchema in the tools list for ListToolsRequestHandler.
    const tools = [
      scanProjectDirsSchema,
      startDevServerSchema,
      getDevStatusSchema,
      getDevLogsSchema,
      stopDevServerSchema,
      restartDevServerSchema,
      getHealthStatusSchema,
      recoverFromStateSchema,
      autoRecoverSchema,
    ];
  • Helper function to check if a process with given PID exists, used in the recovery logic.
    async function checkProcessExists(pid: number): Promise<boolean> {
      try {
        // プロセスが存在するかチェック(kill -0)
        process.kill(pid, 0);
        return true;
      } catch (error) {
        // ESRCH = プロセスが存在しない
        if ((error as NodeJS.ErrnoException).code === 'ESRCH') {
          return false;
        }
        // EPERM = 権限なし(プロセスは存在する)
        if ((error as NodeJS.ErrnoException).code === 'EPERM') {
          return true;
        }
        // その他のエラー
        throw error;
      }
    }
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries full burden for behavioral disclosure. It mentions 'attempt recovery' which implies a mutation operation, but doesn't specify what gets recovered, whether it's destructive to current state, what permissions are needed, or what happens on failure. The description is too vague to understand the tool's actual behavior beyond the basic concept.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is extremely concise (one phrase) but under-specified rather than efficiently informative. While it's front-loaded with the core concept, it lacks necessary detail about what's being recovered. The single sentence doesn't waste words, but fails to provide adequate information for tool selection.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a recovery tool with no annotations and no output schema, the description is incomplete. It doesn't explain what 'saved state' means, what gets recovered, success/failure conditions, or return values. Given the complexity implied by a recovery operation and the lack of structured metadata, the description should provide more context about the operation's scope and outcomes.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With only 1 parameter and 100% schema description coverage, the schema already fully documents the 'force' parameter. The description doesn't add any parameter-specific information beyond what's in the schema, but with zero parameters requiring additional explanation, this meets the baseline expectation. The description doesn't need to compensate for any schema gaps.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose2/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description '保存された状態から復旧を試行' (Attempt recovery from saved state) is a tautological restatement of the tool name 'recover_from_state'. It doesn't specify what type of recovery (system, data, application) or what 'saved state' refers to. While it includes a verb ('復旧を試行' - attempt recovery), it lacks specificity about the resource or scope being recovered.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines1/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides no guidance on when to use this tool versus the 8 sibling tools listed (auto_recover, get_dev_logs, etc.). There's no mention of prerequisites, when recovery should be attempted, or what distinguishes this from 'auto_recover'. The agent receives no help in selecting this tool over alternatives.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

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