poker-mcp 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/README.md +241 -0
  2. package/config/mcp-manifest.json +1713 -0
  3. package/config/package-lock.json +1335 -0
  4. package/config/poker_mcp.code-workspace +8 -0
  5. package/package.json +51 -0
  6. package/src/config/ConfigManager.js +120 -0
  7. package/src/config/default.json +62 -0
  8. package/src/mcp/handlers/bodyHandlers.js +63 -0
  9. package/src/mcp/handlers/buildupFactorHandlers.js +43 -0
  10. package/src/mcp/handlers/calculationHandlers.js +265 -0
  11. package/src/mcp/handlers/detectorHandlers.js +201 -0
  12. package/src/mcp/handlers/index.js +43 -0
  13. package/src/mcp/handlers/sourceHandlers.js +25 -0
  14. package/src/mcp/handlers/transformHandlers.js +26 -0
  15. package/src/mcp/handlers/unitHandlers.js +305 -0
  16. package/src/mcp/handlers/zoneHandlers.js +83 -0
  17. package/src/mcp/middleware/errorHandler.js +49 -0
  18. package/src/mcp/middleware/requestValidator.js +129 -0
  19. package/src/mcp/server.js +76 -0
  20. package/src/mcp/tools/bodyTools.js +185 -0
  21. package/src/mcp/tools/buildupFactorTools.js +82 -0
  22. package/src/mcp/tools/calculationTools.js +58 -0
  23. package/src/mcp/tools/commonTools.js +22 -0
  24. package/src/mcp/tools/detectorTools.js +131 -0
  25. package/src/mcp/tools/index.js +34 -0
  26. package/src/mcp/tools/sourceTools.js +726 -0
  27. package/src/mcp/tools/sourceTools_fixed_part2.js +41 -0
  28. package/src/mcp/tools/transformTools.js +73 -0
  29. package/src/mcp/tools/unitTools.js +137 -0
  30. package/src/mcp/tools/zoneTools.js +65 -0
  31. package/src/mcp_server_stdio_v4.js +45 -0
  32. package/src/routes/restApi.js +184 -0
  33. package/src/services/CalculationService.js +525 -0
  34. package/src/services/DataManager.js +738 -0
  35. package/src/services/TaskManager.js +1622 -0
  36. package/src/utils/MaterialAlternatives.js +189 -0
  37. package/src/utils/errorHandler.js +68 -0
  38. package/src/utils/errors.js +37 -0
  39. package/src/utils/logger.js +24 -0
  40. package/src/utils/logger_no_color.js +28 -0
  41. package/src/utils/mcpErrors.js +225 -0
  42. package/src/validators/CMBValidator.js +191 -0
  43. package/src/validators/DetectorValidator.js +512 -0
  44. package/src/validators/ManifestValidator.js +249 -0
  45. package/src/validators/NuclideValidator.js +171 -0
  46. package/src/validators/PhysicsValidator.js +401 -0
  47. package/src/validators/PhysicsValidatorSimple.js +87 -0
  48. package/src/validators/SourceValidator.js +515 -0
  49. package/src/validators/TransformValidator.js +472 -0
  50. package/src/validators/UnitValidator.js +562 -0
@@ -0,0 +1,515 @@
1
+ // validators/SourceValidator.js
2
+ import { PokerMcpError } from '../utils/mcpErrors.js';
3
+ import { ManifestValidator } from './ManifestValidator.js';
4
+ import { NuclideValidator } from './NuclideValidator.js';
5
+
6
+ /**
7
+ * Source構造の複雑なgeometry/divisionバリデーター
8
+ * マニフェスト仕様に完全準拠した高度なSource構造検証
9
+ */
10
+ export class SourceValidator {
11
+
12
+ /**
13
+ * サポートされるSource型定義
14
+ */
15
+ static SUPPORTED_SOURCE_TYPES = {
16
+ 'POINT': {
17
+ description: '点線源',
18
+ requiresGeometry: false,
19
+ requiresDivision: false,
20
+ requiredFields: ['position']
21
+ },
22
+ 'BOX': {
23
+ description: '直方体線源',
24
+ requiresGeometry: true,
25
+ requiresDivision: true,
26
+ geometryFields: ['vertex', 'edge_1', 'edge_2', 'edge_3'],
27
+ divisionFields: ['edge_1', 'edge_2', 'edge_3']
28
+ },
29
+ 'RPP': {
30
+ description: '軸平行直方体線源',
31
+ requiresGeometry: true,
32
+ requiresDivision: true,
33
+ geometryFields: ['min', 'max'],
34
+ divisionFields: ['edge_1', 'edge_2', 'edge_3']
35
+ },
36
+ 'SPH': {
37
+ description: '球体線源',
38
+ requiresGeometry: true,
39
+ requiresDivision: true,
40
+ geometryFields: ['center', 'radius'],
41
+ divisionFields: ['r', 'theta', 'phi']
42
+ },
43
+ 'RCC': {
44
+ description: '円柱線源',
45
+ requiresGeometry: true,
46
+ requiresDivision: true,
47
+ geometryFields: ['bottom_center', 'height_vector', 'radius'],
48
+ divisionFields: ['r', 'phi', 'z']
49
+ }
50
+ };
51
+
52
+ /**
53
+ * 分割タイプの定義
54
+ */
55
+ static DIVISION_TYPES = {
56
+ 'UNIFORM': { description: '均等分割', default: true },
57
+ 'GAUSS_FIRST': { description: 'ガウス分割(最初に集中)' },
58
+ 'GAUSS_LAST': { description: 'ガウス分割(最後に集中)' },
59
+ 'GAUSS_BOTH': { description: 'ガウス分割(両端に集中)' },
60
+ 'GAUSS_CENTER': { description: 'ガウス分割(中央に集中)' }
61
+ };
62
+
63
+ /**
64
+ * Source基本情報の検証
65
+ */
66
+ static validateSourceBasics(sourceData) {
67
+ const { name, type, inventory } = sourceData;
68
+
69
+ // 基本フィールドの検証
70
+ ManifestValidator.validateObjectName(name, 'source name');
71
+
72
+ if (!type || !this.SUPPORTED_SOURCE_TYPES[type]) {
73
+ throw PokerMcpError.validationError(
74
+ `Unsupported source type: ${type}. Supported types: ${Object.keys(this.SUPPORTED_SOURCE_TYPES).join(', ')}`,
75
+ 'type',
76
+ type
77
+ );
78
+ }
79
+
80
+ // インベントリの検証
81
+ NuclideValidator.validateInventory(inventory);
82
+
83
+ return true;
84
+ }
85
+
86
+ /**
87
+ * POINT線源の検証
88
+ */
89
+ static validatePointSource(sourceData) {
90
+ const { position } = sourceData;
91
+
92
+ if (!position) {
93
+ throw PokerMcpError.validationError(
94
+ 'POINT source requires position',
95
+ 'position',
96
+ position
97
+ );
98
+ }
99
+
100
+ ManifestValidator.validateCoordinateString(position, 'position');
101
+
102
+ // POINT線源では geometry と division は不要
103
+ if (sourceData.geometry) {
104
+ console.warn('POINT source does not require geometry parameter');
105
+ }
106
+
107
+ if (sourceData.division) {
108
+ console.warn('POINT source does not require division parameter');
109
+ }
110
+
111
+ return true;
112
+ }
113
+
114
+ /**
115
+ * BOX線源のgeometry検証
116
+ */
117
+ static validateBoxGeometry(geometry) {
118
+ const { vertex, edge_1, edge_2, edge_3, transform } = geometry;
119
+
120
+ // 必須フィールドの検証
121
+ ManifestValidator.validateCoordinateString(vertex, 'geometry.vertex');
122
+ ManifestValidator.validateCoordinateString(edge_1, 'geometry.edge_1');
123
+ ManifestValidator.validateCoordinateString(edge_2, 'geometry.edge_2');
124
+ ManifestValidator.validateCoordinateString(edge_3, 'geometry.edge_3');
125
+
126
+ // エッジベクトルの物理的妥当性チェック
127
+ const edges = [edge_1, edge_2, edge_3];
128
+ for (let i = 0; i < 3; i++) {
129
+ const [x, y, z] = edges[i].split(/\s+/).map(Number);
130
+ const length = Math.sqrt(x*x + y*y + z*z);
131
+ if (length < 1e-10) {
132
+ throw PokerMcpError.validationError(
133
+ `BOX geometry edge_${i+1} cannot be zero vector`,
134
+ `geometry.edge_${i+1}`,
135
+ edges[i]
136
+ );
137
+ }
138
+ }
139
+
140
+ // Transform参照の検証(存在する場合)
141
+ if (transform) {
142
+ ManifestValidator.validateObjectName(transform, 'geometry.transform');
143
+ }
144
+
145
+ return true;
146
+ }
147
+
148
+ /**
149
+ * RPP線源のgeometry検証
150
+ */
151
+ static validateRppGeometry(geometry) {
152
+ const { min, max, transform } = geometry;
153
+
154
+ // 必須フィールドの検証
155
+ ManifestValidator.validateCoordinateString(min, 'geometry.min');
156
+ ManifestValidator.validateCoordinateString(max, 'geometry.max');
157
+
158
+ // 最小・最大座標の妥当性チェック
159
+ const [minX, minY, minZ] = min.split(/\s+/).map(Number);
160
+ const [maxX, maxY, maxZ] = max.split(/\s+/).map(Number);
161
+
162
+ if (minX >= maxX || minY >= maxY || minZ >= maxZ) {
163
+ throw PokerMcpError.validationError(
164
+ 'RPP geometry: min coordinates must be less than max coordinates',
165
+ 'geometry',
166
+ { min, max }
167
+ );
168
+ }
169
+
170
+ // Transform参照の検証(存在する場合)
171
+ if (transform) {
172
+ ManifestValidator.validateObjectName(transform, 'geometry.transform');
173
+ }
174
+
175
+ return true;
176
+ }
177
+
178
+ /**
179
+ * SPH線源のgeometry検証
180
+ */
181
+ static validateSphGeometry(geometry) {
182
+ const { center, radius, transform } = geometry;
183
+
184
+ // 必須フィールドの検証
185
+ ManifestValidator.validateCoordinateString(center, 'geometry.center');
186
+ ManifestValidator.validatePositiveRadius(radius, 'geometry.radius');
187
+
188
+ // Transform参照の検証(存在する場合)
189
+ if (transform) {
190
+ ManifestValidator.validateObjectName(transform, 'geometry.transform');
191
+ }
192
+
193
+ return true;
194
+ }
195
+
196
+ /**
197
+ * RCC線源のgeometry検証
198
+ */
199
+ static validateRccGeometry(geometry) {
200
+ const { bottom_center, height_vector, radius, transform } = geometry;
201
+
202
+ // 必須フィールドの検証
203
+ ManifestValidator.validateCoordinateString(bottom_center, 'geometry.bottom_center');
204
+ ManifestValidator.validateCoordinateString(height_vector, 'geometry.height_vector');
205
+ ManifestValidator.validatePositiveRadius(radius, 'geometry.radius');
206
+
207
+ // 高さベクトルの妥当性チェック
208
+ const [hx, hy, hz] = height_vector.split(/\s+/).map(Number);
209
+ const height = Math.sqrt(hx*hx + hy*hy + hz*hz);
210
+ if (height < 1e-10) {
211
+ throw PokerMcpError.validationError(
212
+ 'RCC geometry height_vector cannot be zero vector',
213
+ 'geometry.height_vector',
214
+ height_vector
215
+ );
216
+ }
217
+
218
+ // Transform参照の検証(存在する場合)
219
+ if (transform) {
220
+ ManifestValidator.validateObjectName(transform, 'geometry.transform');
221
+ }
222
+
223
+ return true;
224
+ }
225
+
226
+ /**
227
+ * Source geometry全体の検証
228
+ */
229
+ static validateSourceGeometry(type, geometry) {
230
+ const sourceType = this.SUPPORTED_SOURCE_TYPES[type];
231
+
232
+ if (!sourceType.requiresGeometry) {
233
+ return true; // geometry不要な線源タイプ
234
+ }
235
+
236
+ if (!geometry || typeof geometry !== 'object') {
237
+ throw PokerMcpError.validationError(
238
+ `${type} source requires geometry object`,
239
+ 'geometry',
240
+ geometry
241
+ );
242
+ }
243
+
244
+ // タイプ別の詳細検証
245
+ switch (type) {
246
+ case 'BOX':
247
+ return this.validateBoxGeometry(geometry);
248
+ case 'RPP':
249
+ return this.validateRppGeometry(geometry);
250
+ case 'SPH':
251
+ return this.validateSphGeometry(geometry);
252
+ case 'RCC':
253
+ return this.validateRccGeometry(geometry);
254
+ default:
255
+ throw PokerMcpError.validationError(
256
+ `Unknown geometry validation for type: ${type}`,
257
+ 'type',
258
+ type
259
+ );
260
+ }
261
+ }
262
+
263
+ /**
264
+ * 分割軸の検証
265
+ */
266
+ static validateDivisionAxis(axis, fieldName) {
267
+ if (!axis || typeof axis !== 'object') {
268
+ throw PokerMcpError.validationError(
269
+ `${fieldName} must be a division axis object`,
270
+ fieldName,
271
+ axis
272
+ );
273
+ }
274
+
275
+ const { type, number, min = 0.0, max = 1.0 } = axis;
276
+
277
+ // 分割タイプの検証
278
+ if (!type || !this.DIVISION_TYPES[type]) {
279
+ throw PokerMcpError.validationError(
280
+ `Invalid division type: ${type}. Valid types: ${Object.keys(this.DIVISION_TYPES).join(', ')}`,
281
+ `${fieldName}.type`,
282
+ type
283
+ );
284
+ }
285
+
286
+ // 分割数の検証
287
+ ManifestValidator.validateGridDivision(number, `${fieldName}.number`);
288
+
289
+ // 分割範囲の検証
290
+ if (typeof min !== 'number' || typeof max !== 'number') {
291
+ throw PokerMcpError.validationError(
292
+ `${fieldName} min and max must be numbers`,
293
+ fieldName,
294
+ { min, max }
295
+ );
296
+ }
297
+
298
+ if (min < 0.0 || min > 1.0 || max < 0.0 || max > 1.0) {
299
+ throw PokerMcpError.validationError(
300
+ `${fieldName} min and max must be between 0.0 and 1.0`,
301
+ fieldName,
302
+ { min, max }
303
+ );
304
+ }
305
+
306
+ if (min >= max) {
307
+ throw PokerMcpError.validationError(
308
+ `${fieldName} min must be less than max`,
309
+ fieldName,
310
+ { min, max }
311
+ );
312
+ }
313
+
314
+ return true;
315
+ }
316
+
317
+ /**
318
+ * BOX/RPP線源のdivision検証
319
+ */
320
+ static validateCartesianDivision(division) {
321
+ const { edge_1, edge_2, edge_3 } = division;
322
+
323
+ this.validateDivisionAxis(edge_1, 'division.edge_1');
324
+ this.validateDivisionAxis(edge_2, 'division.edge_2');
325
+ this.validateDivisionAxis(edge_3, 'division.edge_3');
326
+
327
+ return true;
328
+ }
329
+
330
+ /**
331
+ * SPH線源のdivision検証
332
+ */
333
+ static validateSphericalDivision(division) {
334
+ const { r, theta, phi } = division;
335
+
336
+ this.validateDivisionAxis(r, 'division.r');
337
+ this.validateDivisionAxis(theta, 'division.theta');
338
+ this.validateDivisionAxis(phi, 'division.phi');
339
+
340
+ // 球面座標特有の検証
341
+ if (theta.max > 1.0) {
342
+ console.warn('SPH division theta.max > 1.0 may represent angles > π');
343
+ }
344
+
345
+ if (phi.max > 1.0) {
346
+ console.warn('SPH division phi.max > 1.0 may represent angles > 2π');
347
+ }
348
+
349
+ return true;
350
+ }
351
+
352
+ /**
353
+ * RCC線源のdivision検証
354
+ */
355
+ static validateCylindricalDivision(division) {
356
+ const { r, phi, z } = division;
357
+
358
+ this.validateDivisionAxis(r, 'division.r');
359
+ this.validateDivisionAxis(phi, 'division.phi');
360
+ this.validateDivisionAxis(z, 'division.z');
361
+
362
+ // 円柱座標特有の検証
363
+ if (phi.max > 1.0) {
364
+ console.warn('RCC division phi.max > 1.0 may represent angles > 2π');
365
+ }
366
+
367
+ return true;
368
+ }
369
+
370
+ /**
371
+ * Source division全体の検証
372
+ */
373
+ static validateSourceDivision(type, division) {
374
+ const sourceType = this.SUPPORTED_SOURCE_TYPES[type];
375
+
376
+ if (!sourceType.requiresDivision) {
377
+ return true; // division不要な線源タイプ
378
+ }
379
+
380
+ if (!division || typeof division !== 'object') {
381
+ throw PokerMcpError.validationError(
382
+ `${type} source requires division object`,
383
+ 'division',
384
+ division
385
+ );
386
+ }
387
+
388
+ // タイプ別の詳細検証
389
+ switch (type) {
390
+ case 'BOX':
391
+ case 'RPP':
392
+ return this.validateCartesianDivision(division);
393
+ case 'SPH':
394
+ return this.validateSphericalDivision(division);
395
+ case 'RCC':
396
+ return this.validateCylindricalDivision(division);
397
+ default:
398
+ throw PokerMcpError.validationError(
399
+ `Unknown division validation for type: ${type}`,
400
+ 'type',
401
+ type
402
+ );
403
+ }
404
+ }
405
+
406
+ /**
407
+ * カットオフ率の検証(必須パラメータ)
408
+ */
409
+ static validateCutoffRate(cutoff_rate) {
410
+ if (cutoff_rate === undefined) {
411
+ throw PokerMcpError.validationError(
412
+ 'cutoff_rate parameter is required for radiation shielding calculation accuracy',
413
+ 'cutoff_rate',
414
+ cutoff_rate,
415
+ -32050
416
+ );
417
+ }
418
+
419
+ ManifestValidator.validateCutoffRate(cutoff_rate, 'cutoff_rate');
420
+
421
+ return true;
422
+ }
423
+
424
+ /**
425
+ * Source構造全体の包括的検証
426
+ */
427
+ static validateCompleteSourceStructure(sourceData) {
428
+ const { name, type, position, geometry, division, inventory, cutoff_rate } = sourceData;
429
+
430
+ // 基本情報の検証
431
+ this.validateSourceBasics(sourceData);
432
+
433
+ // タイプ別の詳細検証
434
+ if (type === 'POINT') {
435
+ this.validatePointSource(sourceData);
436
+ } else {
437
+ // 複雑なSource構造の検証
438
+ this.validateSourceGeometry(type, geometry);
439
+ this.validateSourceDivision(type, division);
440
+ }
441
+
442
+ // カットオフ率の検証
443
+ this.validateCutoffRate(cutoff_rate);
444
+
445
+ return {
446
+ name,
447
+ type,
448
+ isPoint: type === 'POINT',
449
+ requiresGeometry: this.SUPPORTED_SOURCE_TYPES[type].requiresGeometry,
450
+ requiresDivision: this.SUPPORTED_SOURCE_TYPES[type].requiresDivision,
451
+ inventoryCount: inventory.length,
452
+ hasTransform: !!(geometry && geometry.transform),
453
+ divisionComplexity: this._calculateDivisionComplexity(type, division)
454
+ };
455
+ }
456
+
457
+ /**
458
+ * Division複雑度の計算
459
+ * @private
460
+ */
461
+ static _calculateDivisionComplexity(type, division) {
462
+ if (type === 'POINT' || !division) {
463
+ return 0;
464
+ }
465
+
466
+ let complexity = 1;
467
+ const sourceType = this.SUPPORTED_SOURCE_TYPES[type];
468
+
469
+ for (const field of sourceType.divisionFields) {
470
+ if (division[field]) {
471
+ complexity *= division[field].number || 1;
472
+ }
473
+ }
474
+
475
+ return complexity;
476
+ }
477
+
478
+ /**
479
+ * Source構造の最適化提案
480
+ */
481
+ static analyzeSrcStructureOptimization(sourceData) {
482
+ const analysis = this.validateCompleteSourceStructure(sourceData);
483
+ const suggestions = [];
484
+
485
+ // 分割数最適化の提案
486
+ if (analysis.divisionComplexity > 1000) {
487
+ suggestions.push({
488
+ type: 'performance',
489
+ message: `High division complexity (${analysis.divisionComplexity}). Consider reducing division numbers for better performance.`
490
+ });
491
+ }
492
+
493
+ // 不要なgeometry/division警告
494
+ if (analysis.isPoint && (sourceData.geometry || sourceData.division)) {
495
+ suggestions.push({
496
+ type: 'cleanup',
497
+ message: 'POINT source does not need geometry or division parameters.'
498
+ });
499
+ }
500
+
501
+ // インベントリ最適化
502
+ if (analysis.inventoryCount > 10) {
503
+ suggestions.push({
504
+ type: 'complexity',
505
+ message: `Large inventory (${analysis.inventoryCount} nuclides). Consider grouping similar nuclides.`
506
+ });
507
+ }
508
+
509
+ return {
510
+ analysis,
511
+ suggestions,
512
+ isOptimal: suggestions.length === 0
513
+ };
514
+ }
515
+ }