Skip to main content
Glama
Hirao-Y

Poker Task Management MCP

by Hirao-Y

poker_executeCalculation

Execute radiation shielding calculations using YAML configuration files to generate dose summaries and output files for analysis.

Instructions

作成したYAMLファイルを使用してpoker_cuiで放射線遮蔽計算を実行します

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
output_filesNo出力ファイル指定(入力YAMLファイルと同じフォルダに自動作成、全てYAML形式)
summary_optionsNoサマリー出力オプション(注意: show_source_dataとshow_total_doseの少なくとも一方は必須です)
yaml_fileYes計算に使用するYAMLファイル名(拡張子.yamlを含む)

Implementation Reference

  • MCP tool handler that validates input arguments, performs pre-validation checks, executes calculation via service, verifies outputs, and returns formatted response with error handling.
    async executeCalculation(args) { try { // 引数検証 if (!args.yaml_file) { throw new ValidationError('YAML file is required', 'yaml_file', args.yaml_file); } // 絶対パス形式の事前チェック(詳細検証はサービス層で実行) const absolutePathPattern = /^([a-zA-Z]:[\\\/]|\/)/; if (!absolutePathPattern.test(args.yaml_file)) { throw new ValidationError( 'YAML file must be specified with absolute path. Examples: C:\\path\\to\\file.yaml or /path/to/file.yaml', 'yaml_file', args.yaml_file ); } // YAML拡張子チェック if (!args.yaml_file.match(/\.(yaml|yml)$/i)) { throw new ValidationError( 'YAML file must have .yaml or .yml extension', 'yaml_file', args.yaml_file ); } // サマリーオプション検証 const summaryOptions = args.summary_options || {}; if (summaryOptions.show_source_data === false && summaryOptions.show_total_dose === false) { logger.warn('Both show_source_data and show_total_dose are false, this may result in minimal output'); } // 出力ファイルの自動パス解決 const outputFiles = args.output_files || {}; const resolvedOutputFiles = {}; if (Object.keys(outputFiles).length > 0) { // 入力YAMLファイルのディレクトリを取得 const inputDir = path.dirname(args.yaml_file); // 各出力ファイルの絶対パス化 for (const [key, fileName] of Object.entries(outputFiles)) { if (fileName) { // ファイル名の拡張子チェック if (!fileName.match(/\.(yaml|yml)$/i)) { throw new ValidationError( `Output file ${key} must have .yaml or .yml extension`, `output_files.${key}`, fileName ); } // 絶対パスに解決 resolvedOutputFiles[key] = path.join(inputDir, fileName); logger.debug('Output file path resolved', { key, fileName, inputDir, resolvedPath: resolvedOutputFiles[key] }); } } } // 出力ファイル検証(従来の検証は不要、上記で実施済み) logger.info('Starting radiation shielding calculation', { yamlFile: args.yaml_file, summaryOptions, outputFiles: outputFiles, resolvedOutputFiles }); // 計算実行(統合検証付き、絶対パス化済みの出力ファイルパスを使用) const result = await calculationService.executeWithValidation( args.yaml_file, summaryOptions, resolvedOutputFiles, // 絶対パス化済み undefined, // timeout(デフォルト値を使用) taskManager.dataManager // 事前検証用DataManager ); // 事前検証で重大エラーが検出された場合の処理 if (result.success === false && result.stage === 'pre_validation') { logger.error('Pre-calculation validation failed', { yamlFile: args.yaml_file, criticalErrors: result.criticalErrors }); return { success: false, error: result.error, error_type: 'PRE_VALIDATION_FAILED', message: result.message, mcp_error_code: -32048, // Custom code for pre-validation failure validation_details: result.validationResult, critical_errors: result.criticalErrors, details: { category: 'pre_validation_error', recoverable: true, suggestions: [ 'Check daughter nuclide configurations', 'Review material definitions', 'Ensure all required parameters are properly defined', 'Note: Geometry collisions will not block calculation' ] } }; } // 出力ファイル検証(絶対パス化済みのパスを使用) const fileVerification = await calculationService.verifyOutputFiles(resolvedOutputFiles); // 成功レスポンス const response = { success: true, message: 'Radiation shielding calculation completed successfully', calculation: { input_file: args.yaml_file, execution_time_ms: result.executionTime, timestamp: result.summary.timestamp, options: result.summary.options }, validation: { pre_calculation_performed: result.preValidation?.performed || false, pre_calculation_passed: result.preValidation?.passed || false, details: result.preValidation?.details || 'No pre-validation performed' }, outputs: { console: { stdout: result.outputs.stdout ? 'Available (see details)' : 'Empty', stderr: result.outputs.stderr ? 'Available (see details)' : 'Empty', stdout_length: result.outputs.stdout.length, stderr_length: result.outputs.stderr.length }, files: fileVerification }, details: { stdout: result.outputs.stdout, stderr: result.outputs.stderr, summary_options_applied: result.summary.options, poker_cui_command: 'poker_cui executed successfully' } }; // 出力ファイル生成の警告 if (!fileVerification.allFilesGenerated) { response.warnings = ['Some output files were not generated. Check calculation logs for details.']; } logger.info('Calculation completed successfully', { yamlFile: args.yaml_file, executionTime: result.executionTime, outputFiles: Object.keys(fileVerification).filter(k => k !== 'allFilesGenerated') }); return response; } catch (error) { logger.error('executeCalculation handler error', { args, error: error.message, errorType: error.constructor.name }); // CalculationErrorの場合はMCPエラーコードも含める if (error instanceof CalculationError) { return { success: false, error: error.message, error_type: error.code, context: error.context, mcp_error_code: error.mcpErrorCode, details: { category: 'calculation_error', recoverable: this._isRecoverableError(error.code), suggestions: this._getErrorSuggestions(error.code, error.context) } }; } // ValidationErrorの場合 if (error instanceof ValidationError) { return { success: false, error: error.message, error_type: 'VALIDATION_ERROR', field: error.field, value: error.value, mcp_error_code: -32047, // Invalid calculation parameters details: { category: 'parameter_error', recoverable: true, suggestions: ['Check parameter format and values', 'Ensure all required parameters are provided'] } }; } // その他のエラー throw error; } },
  • Tool schema defining input parameters: yaml_file (required), summary_options, output_files with validation patterns and descriptions.
    name: 'poker_executeCalculation', description: '作成したYAMLファイルを使用してpoker_cuiで放射線遮蔽計算を実行します', inputSchema: { type: 'object', properties: { yaml_file: { type: 'string', description: '計算に使用するYAMLファイル名(拡張子.yamlを含む)', pattern: '^[a-zA-Z0-9_\\-\\.]+\\.(yaml|yml)$' }, summary_options: { type: 'object', description: 'サマリー出力オプション(注意: show_source_dataとshow_total_doseの少なくとも一方は必須です)', properties: { show_parameters: { type: 'boolean', description: '入力パラメータをサマリーに表示(-pオプション)', default: false }, show_source_data: { type: 'boolean', description: '各線源による計算データ及び線量をサマリーに表示(-sオプション)', default: true }, show_total_dose: { type: 'boolean', description: '各検出器に対する全線源からの総和線量をサマリーに表示(-tオプション)', default: true } }, additionalProperties: false }, output_files: { type: 'object', description: '出力ファイル指定(入力YAMLファイルと同じフォルダに自動作成、全てYAML形式)', properties: { summary_file: { type: 'string', description: '出力サマリーファイル名(-oオプション、ファイル名のみ指定、自動的に入力ファイルと同じディレクトリに配置)', pattern: '^[a-zA-Z0-9_\\-\\.]+\\.(yaml|yml)$' }, dose_file: { type: 'string', description: '線量ファイル名(-dオプション、ファイル名のみ指定、自動的に入力ファイルと同じディレクトリに配置)', pattern: '^[a-zA-Z0-9_\\-\\.]+\\.(yaml|yml)$' } }, additionalProperties: false } }, required: ['yaml_file'], additionalProperties: false }
  • Registers the tool call handler in MCP server, mapping 'poker_executeCalculation' to 'executeCalculation' by removing 'poker_' prefix and invoking the corresponding handler function.
    this.server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; logger.info(`MCP Tool実行: ${name}`, { args }); // ハンドラー名をツール名から生成(プレフィックス除去) const handlerName = name.replace('poker_', ''); const handler = this.handlers[handlerName]; if (!handler) { throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`); } return await safeExecute(async () => handler(args), { tool: name })(); });
  • Helper service implementing integrated validation (daughter nuclides, geometry), executes core calculation, handles blocking conditions like daughter nuclide confirmation.
    async executeWithValidation(yamlFile, summaryOptions = {}, outputFiles = {}, timeout = this.defaultTimeout, dataManager = null) { try { logger.info('統合検証付き計算実行を開始', { yamlFile }); // 事前検証の実行 if (dataManager) { logger.info('計算実行前の統合検証を実行中...'); const validationResult = await dataManager.performPreCalculationValidation(); // 立体衝突チェックは警告のみとし、計算を中断しない if (validationResult.collisionCheck?.hasCollisions) { logger.warn('立体干渉が検出されましたが、計算を続行します', { collisions: validationResult.collisionCheck.collisions, totalIssues: validationResult.collisionCheck.totalIssues }); } // 子孫核種チェックは維持(物理的に必須) if (validationResult.daughterNuclideCheck?.totalAdditions > 0 && !dataManager.daughterNuclideCheckDisabled) { logger.info('子孫核種が検出されました - 計算を中断してユーザー確認を要求'); return { success: false, stage: 'requires_confirmation', status: 'requires_confirmation', calculation_blocked: true, error: 'DAUGHTER_NUCLIDE_CONFIRMATION_REQUIRED', message: '子孫核種が検出されました。poker_confirmDaughterNuclidesで確認してください', daughter_nuclide_suggestions: this.formatDaughterNuclideSuggestions(validationResult.daughterNuclideCheck), total_additions: validationResult.daughterNuclideCheck.totalAdditions, available_actions: [ 'poker_confirmDaughterNuclides action="check" - 詳細確認', 'poker_confirmDaughterNuclides action="confirm" - 承認して適用', 'poker_confirmDaughterNuclides action="confirm_with_modifications" - 修正して適用', 'poker_confirmDaughterNuclides action="reject" - 拒否' ], next_step: 'poker_confirmDaughterNuclidesを実行後、再度poker_executeCalculationを実行してください' }; } // 立体衝突以外の重大エラーのみチェック const nonCollisionErrors = validationResult.criticalErrors?.filter( error => error.type !== 'collision_detected' ) || []; if (nonCollisionErrors.length > 0) { logger.error('計算実行前に解決が必要な重大エラーを検出', { criticalErrorCount: nonCollisionErrors.length }); return { success: false, stage: 'pre_validation', error: 'CRITICAL_VALIDATION_ERRORS', message: '計算実行前に解決が必要な重大エラーがあります', validationResult, criticalErrors: nonCollisionErrors }; } if (!validationResult.overall) { logger.warn('検証で警告が検出されましたが、計算を継続します', { warningCount: validationResult.warnings.length }); } // 検証結果をログに記録 logger.info('事前検証完了', { overall: validationResult.overall, collisionCheck: validationResult.collisionCheck?.hasCollisions || false, daughterNuclideIssues: validationResult.daughterNuclideCheck?.totalAdditions || 0, enhancedValidationPassed: validationResult.enhancedValidation?.overall || false }); } // 通常の計算実行 const calculationResult = await this.executeCalculation(yamlFile, summaryOptions, outputFiles, timeout); // poker_cuiがエラーを返した場合、事後診断を実行 if (!calculationResult.success && dataManager) { logger.info('計算エラーが発生したため、事後診断を実行します'); const postValidation = await dataManager.performPreCalculationValidation(); // エラー診断情報を結果に追加 calculationResult.diagnostics = { performed: true, collisionCheck: postValidation.collisionCheck, suggestions: [] }; if (postValidation.collisionCheck?.hasCollisions) { calculationResult.diagnostics.suggestions.push( '立体干渉が検出されました。組み合わせ立体(CMB)の使用を検討してください' ); } } // 結果に検証情報を追加 if (dataManager) { calculationResult.preValidation = { performed: true, passed: true, details: 'Pre-calculation validation completed with warnings only' }; } return calculationResult; } catch (error) { logger.error('統合検証付き計算実行でエラー', { error: error.message, yamlFile }); throw new CalculationError(`統合計算実行エラー: ${error.message}`, 'INTEGRATED_EXECUTION_ERROR'); } }
  • Low-level helper that spawns the 'poker_cui' external command, manages process I/O, timeout, and error conditions.
    async _executePokercui(args, timeout, context) { return new Promise((resolve, reject) => { const startTime = Date.now(); let isTimedOut = false; let isCompleted = false; const child = spawn(this.pokercuiCommand, args, { stdio: 'pipe', shell: true, env: { ...process.env } }); let stdout = ''; let stderr = ''; // データ収集 child.stdout.on('data', (data) => { const chunk = data.toString(); stdout += chunk; logger.debug('poker_cui stdout chunk', { chunk: chunk.substring(0, 200) }); }); child.stderr.on('data', (data) => { const chunk = data.toString(); stderr += chunk; logger.debug('poker_cui stderr chunk', { chunk: chunk.substring(0, 200) }); }); // プロセス終了処理 child.on('close', (code, signal) => { if (isCompleted) return; isCompleted = true; const endTime = Date.now(); const executionTime = endTime - startTime; logger.info('poker_cui execution completed', { code, signal, executionTime, stdoutLength: stdout.length, stderrLength: stderr.length }); if (isTimedOut) { reject(new CalculationError( `Calculation timed out after ${timeout}ms`, 'CALCULATION_TIMEOUT', { ...context, executionTime, timeout }, -32044 )); return; } if (code !== 0) { reject(new CalculationError( `poker_cui execution failed with exit code ${code}`, 'CALCULATION_EXECUTION_FAILED', { ...context, exitCode: code, signal, stdout: stdout.substring(0, 1000), stderr: stderr.substring(0, 1000), executionTime }, -32043 )); return; } // 成功時の結果処理 resolve({ success: true, executionTime, outputs: { stdout: stdout.trim(), stderr: stderr.trim() }, files: this._identifyOutputFiles(context.outputFiles), summary: { message: 'Calculation completed successfully', yamlFile: context.yamlFile, options: context.summaryOptions, timestamp: new Date().toISOString() } }); }); // エラー処理 child.on('error', (error) => { if (isCompleted) return; isCompleted = true; logger.error('poker_cui process error', { error: error.message, context }); if (error.code === 'ENOENT') { reject(new CalculationError( 'poker_cui command not found', 'POKER_CUI_NOT_AVAILABLE', { ...context, systemError: error.message }, -32042 )); } else { reject(new CalculationError( `Process execution error: ${error.message}`, 'CALCULATION_EXECUTION_FAILED', { ...context, systemError: error.message }, -32043 )); } }); // タイムアウト処理 const timeoutId = setTimeout(() => { if (isCompleted) return; isTimedOut = true; logger.warn('poker_cui calculation timeout, killing process', { timeout, context }); child.kill('SIGKILL'); }, timeout); // プロセス完了時にタイマーをクリア child.on('close', () => { clearTimeout(timeoutId); }); }); }

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/Hirao-Y/poker_mcp'

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