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,41 @@
1
+ 1000 }, min: { type: 'number', minimum: 0.0, maximum: 1.0 }, max: { type: 'number', minimum: 0.0, maximum: 1.0 } }, required: ['type', 'number'] },
2
+ phi: { type: 'object', properties: { type: { enum: ['UNIFORM', 'GAUSS_FIRST', 'GAUSS_LAST', 'GAUSS_BOTH', 'GAUSS_CENTER'] }, number: { type: 'integer', minimum: 1, maximum: 1000 }, min: { type: 'number', minimum: 0.0, maximum: 1.0 }, max: { type: 'number', minimum: 0.0, maximum: 1.0 } }, required: ['type', 'number'] }
3
+ },
4
+ required: ['r', 'theta', 'phi']
5
+ },
6
+ {
7
+ title: 'RCC線源分割',
8
+ properties: {
9
+ r: { type: 'object', properties: { type: { enum: ['UNIFORM', 'GAUSS_FIRST', 'GAUSS_LAST', 'GAUSS_BOTH', 'GAUSS_CENTER'] }, number: { type: 'integer', minimum: 1, maximum: 1000 }, min: { type: 'number', minimum: 0.0, maximum: 1.0 }, max: { type: 'number', minimum: 0.0, maximum: 1.0 } }, required: ['type', 'number'] },
10
+ phi: { type: 'object', properties: { type: { enum: ['UNIFORM', 'GAUSS_FIRST', 'GAUSS_LAST', 'GAUSS_BOTH', 'GAUSS_CENTER'] }, number: { type: 'integer', minimum: 1, maximum: 1000 }, min: { type: 'number', minimum: 0.0, maximum: 1.0 }, max: { type: 'number', minimum: 0.0, maximum: 1.0 } }, required: ['type', 'number'] },
11
+ z: { type: 'object', properties: { type: { enum: ['UNIFORM', 'GAUSS_FIRST', 'GAUSS_LAST', 'GAUSS_BOTH', 'GAUSS_CENTER'] }, number: { type: 'integer', minimum: 1, maximum: 1000 }, min: { type: 'number', minimum: 0.0, maximum: 1.0 }, max: { type: 'number', minimum: 0.0, maximum: 1.0 } }, required: ['type', 'number'] }
12
+ },
13
+ required: ['r', 'phi', 'z']
14
+ }
15
+ ]
16
+ },
17
+ cutoff_rate: {
18
+ type: 'number',
19
+ description: '新しいカットオフレート',
20
+ minimum: 0,
21
+ maximum: 1
22
+ }
23
+ },
24
+ required: ['name']
25
+ }
26
+ },
27
+ {
28
+ name: 'poker_deleteSource',
29
+ description: '放射線源を削除します',
30
+ inputSchema: {
31
+ type: 'object',
32
+ properties: {
33
+ name: {
34
+ type: 'string',
35
+ description: '削除対象線源名'
36
+ }
37
+ },
38
+ required: ['name']
39
+ }
40
+ }
41
+ ];
@@ -0,0 +1,73 @@
1
+ // mcp/tools/transformTools.js
2
+ export const transformTools = [
3
+ {
4
+ name: 'poker_proposeTransform',
5
+ description: '回転・移動変換を提案します',
6
+ inputSchema: {
7
+ type: 'object',
8
+ properties: {
9
+ name: {
10
+ type: 'string',
11
+ description: '変換の一意な名前'
12
+ },
13
+ operations: {
14
+ type: 'array',
15
+ description: '変換操作の配列',
16
+ items: {
17
+ type: 'object',
18
+ description: '変換操作(rotate_around_x, rotate_around_y, rotate_around_z, translate)',
19
+ properties: {
20
+ rotate_around_x: { type: 'number', description: 'X軸周りの回転角度(度)' },
21
+ rotate_around_y: { type: 'number', description: 'Y軸周りの回転角度(度)' },
22
+ rotate_around_z: { type: 'number', description: 'Z軸周りの回転角度(度)' },
23
+ translate: { type: 'string', description: '平行移動ベクトル (x y z形式)' }
24
+ }
25
+ },
26
+ minItems: 1
27
+ }
28
+ },
29
+ required: ['name', 'operations']
30
+ }
31
+ },
32
+ {
33
+ name: 'poker_updateTransform',
34
+ description: '既存変換の操作を更新します',
35
+ inputSchema: {
36
+ type: 'object',
37
+ properties: {
38
+ name: {
39
+ type: 'string',
40
+ description: '更新する変換名'
41
+ },
42
+ operations: {
43
+ type: 'array',
44
+ description: '新しい変換操作の配列',
45
+ items: {
46
+ type: 'object',
47
+ properties: {
48
+ rotate_around_x: { type: 'number' },
49
+ rotate_around_y: { type: 'number' },
50
+ rotate_around_z: { type: 'number' },
51
+ translate: { type: 'string' }
52
+ }
53
+ }
54
+ }
55
+ },
56
+ required: ['name']
57
+ }
58
+ },
59
+ {
60
+ name: 'poker_deleteTransform',
61
+ description: '変換を削除します',
62
+ inputSchema: {
63
+ type: 'object',
64
+ properties: {
65
+ name: {
66
+ type: 'string',
67
+ description: '削除する変換名'
68
+ }
69
+ },
70
+ required: ['name']
71
+ }
72
+ }
73
+ ];
@@ -0,0 +1,137 @@
1
+ // mcp/tools/unitTools.js
2
+ export const unitTools = [
3
+ {
4
+ name: 'poker_proposeUnit',
5
+ description: '単位設定セクションを提案します(YAMLファイルに未存在の場合のみ)- 4キー完全性保証',
6
+ inputSchema: {
7
+ type: 'object',
8
+ properties: {
9
+ length: {
10
+ type: 'string',
11
+ enum: ['m', 'cm', 'mm'],
12
+ description: '長さの単位',
13
+ default: 'cm'
14
+ },
15
+ angle: {
16
+ type: 'string',
17
+ enum: ['radian', 'degree'],
18
+ description: '角度の単位',
19
+ default: 'radian'
20
+ },
21
+ density: {
22
+ type: 'string',
23
+ enum: ['g/cm3'],
24
+ description: '密度の単位',
25
+ default: 'g/cm3'
26
+ },
27
+ radioactivity: {
28
+ type: 'string',
29
+ enum: ['Bq'],
30
+ description: '放射能の単位',
31
+ default: 'Bq'
32
+ }
33
+ },
34
+ required: ['length', 'angle', 'density', 'radioactivity'],
35
+ additionalProperties: false,
36
+ title: '4キー必須単位構造',
37
+ description: '全4キー(length, angle, density, radioactivity)が必須です。部分指定は不可。'
38
+ }
39
+ },
40
+ {
41
+ name: 'poker_getUnit',
42
+ description: '現在の単位設定を取得します(4つのキーすべてを返却)- 完全性保証',
43
+ inputSchema: {
44
+ type: 'object',
45
+ properties: {},
46
+ required: [],
47
+ additionalProperties: false,
48
+ title: '4キー完全取得',
49
+ description: '常に4つの単位キー(length, angle, density, radioactivity)すべてを返却します。'
50
+ }
51
+ },
52
+ {
53
+ name: 'poker_updateUnit',
54
+ description: '既存単位設定を更新します(部分更新可能だが4つのキーは常に維持)- 完全性保証',
55
+ inputSchema: {
56
+ type: 'object',
57
+ properties: {
58
+ length: {
59
+ type: 'string',
60
+ enum: ['m', 'cm', 'mm'],
61
+ description: '新しい長さの単位'
62
+ },
63
+ angle: {
64
+ type: 'string',
65
+ enum: ['radian', 'degree'],
66
+ description: '新しい角度の単位'
67
+ },
68
+ density: {
69
+ type: 'string',
70
+ enum: ['g/cm3'],
71
+ description: '新しい密度の単位'
72
+ },
73
+ radioactivity: {
74
+ type: 'string',
75
+ enum: ['Bq'],
76
+ description: '新しい放射能の単位'
77
+ }
78
+ },
79
+ minProperties: 1,
80
+ additionalProperties: false,
81
+ title: '4キー保持更新',
82
+ description: '部分更新可能ですが、結果として4キー構造は常に保持されます。'
83
+ }
84
+ },
85
+ {
86
+ name: 'poker_validateUnitIntegrity',
87
+ description: '単位系の4キー完全性と物理的整合性を包括検証します',
88
+ inputSchema: {
89
+ type: 'object',
90
+ properties: {
91
+ includeSystemAnalysis: {
92
+ type: 'boolean',
93
+ description: 'システム全体での単位使用状況分析を含めるか',
94
+ default: true
95
+ },
96
+ generateReport: {
97
+ type: 'boolean',
98
+ description: '詳細診断レポートを生成するか',
99
+ default: true
100
+ }
101
+ },
102
+ additionalProperties: false,
103
+ title: '単位完全性検証',
104
+ description: '4キー構造の完全性、物理的整合性、システム内使用状況を包括的に検証'
105
+ }
106
+ },
107
+ {
108
+ name: 'poker_analyzeUnitConversion',
109
+ description: '異なる単位系間の変換係数を分析・計算します',
110
+ inputSchema: {
111
+ type: 'object',
112
+ properties: {
113
+ targetUnits: {
114
+ type: 'object',
115
+ properties: {
116
+ length: { type: 'string', enum: ['m', 'cm', 'mm'] },
117
+ angle: { type: 'string', enum: ['radian', 'degree'] },
118
+ density: { type: 'string', enum: ['g/cm3'] },
119
+ radioactivity: { type: 'string', enum: ['Bq'] }
120
+ },
121
+ required: ['length', 'angle', 'density', 'radioactivity'],
122
+ additionalProperties: false,
123
+ description: '変換先単位系(4キー必須)'
124
+ },
125
+ includePhysicalAnalysis: {
126
+ type: 'boolean',
127
+ description: '物理的整合性分析を含めるか',
128
+ default: true
129
+ }
130
+ },
131
+ required: ['targetUnits'],
132
+ additionalProperties: false,
133
+ title: '単位変換分析',
134
+ description: '現在の単位系から指定単位系への変換係数計算と物理的整合性分析'
135
+ }
136
+ }
137
+ ];
@@ -0,0 +1,65 @@
1
+ // mcp/tools/zoneTools.js
2
+ export const zoneTools = [
3
+ {
4
+ name: 'poker_proposeZone',
5
+ description: '材料ゾーンを提案します(物理検証付き)',
6
+ inputSchema: {
7
+ type: 'object',
8
+ properties: {
9
+ body_name: {
10
+ type: 'string',
11
+ description: 'ゾーンが適用される立体名'
12
+ },
13
+ material: {
14
+ type: 'string',
15
+ description: '材料名(例:CONCRETE, STEEL, VOID)'
16
+ },
17
+ density: {
18
+ type: 'number',
19
+ description: '密度 (g/cm³)',
20
+ minimum: 0.001,
21
+ maximum: 30.0
22
+ }
23
+ },
24
+ required: ['body_name', 'material']
25
+ }
26
+ },
27
+ {
28
+ name: 'poker_updateZone',
29
+ description: '既存ゾーンの材料や密度を更新します',
30
+ inputSchema: {
31
+ type: 'object',
32
+ properties: {
33
+ body_name: {
34
+ type: 'string',
35
+ description: '更新するゾーンの立体名'
36
+ },
37
+ material: {
38
+ type: 'string',
39
+ description: '新しい材料名'
40
+ },
41
+ density: {
42
+ type: 'number',
43
+ description: '新しい密度 (g/cm³)',
44
+ minimum: 0.001,
45
+ maximum: 30.0
46
+ }
47
+ },
48
+ required: ['body_name']
49
+ }
50
+ },
51
+ {
52
+ name: 'poker_deleteZone',
53
+ description: 'ゾーンを削除します(ATMOSPHERE以外)',
54
+ inputSchema: {
55
+ type: 'object',
56
+ properties: {
57
+ body_name: {
58
+ type: 'string',
59
+ description: '削除するゾーンの立体名'
60
+ }
61
+ },
62
+ required: ['body_name']
63
+ }
64
+ }
65
+ ];
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env node
2
+ // mcp_server_stdio_v4.js - MCP専用版(stdout汚染防止)
3
+ import { PokerMcpServer } from './mcp/server.js';
4
+ import { logger } from './utils/logger.js';
5
+
6
+ async function main() {
7
+ try {
8
+ const server = new PokerMcpServer();
9
+ await server.initialize();
10
+ await server.start();
11
+ } catch (error) {
12
+ logger.error('サーバー起動失敗', { error: error.message });
13
+ // console.errorは削除(stdout汚染防止)
14
+ process.exit(1);
15
+ }
16
+ }
17
+
18
+ // 未処理の例外とプロミス拒否のハンドリング
19
+ process.on('uncaughtException', (error) => {
20
+ logger.error('Uncaught Exception', { error: error.message, stack: error.stack });
21
+ // console.errorは削除(stdout汚染防止)
22
+ process.exit(1);
23
+ });
24
+
25
+ process.on('unhandledRejection', (reason, promise) => {
26
+ logger.error('Unhandled Rejection', { reason: reason?.message || reason, promise });
27
+ // console.errorは削除(stdout汚染防止)
28
+ process.exit(1);
29
+ });
30
+
31
+ // グレースフルシャットダウン
32
+ process.on('SIGINT', () => {
33
+ logger.info('SIGINT受信、サーバーを終了します');
34
+ process.exit(0);
35
+ });
36
+
37
+ process.on('SIGTERM', () => {
38
+ logger.info('SIGTERM受信、サーバーを終了します');
39
+ process.exit(0);
40
+ });
41
+
42
+ main().catch((error) => {
43
+ logger.error('メイン関数エラー', { error: error.message });
44
+ process.exit(1);
45
+ });
@@ -0,0 +1,184 @@
1
+ // src/routes/restApi.js
2
+ import express from 'express';
3
+ import { logger } from '../utils/logger.js';
4
+ import { ValidationError, PhysicsError, DataError } from '../utils/errors.js';
5
+
6
+ export function createRestApiRoutes(taskManager) {
7
+ const router = express.Router();
8
+
9
+ // Bodies endpoints
10
+ router.get('/bodies', async (req, res) => {
11
+ try {
12
+ const bodies = taskManager.data.body || [];
13
+ res.json({
14
+ success: true,
15
+ data: bodies,
16
+ count: bodies.length
17
+ });
18
+ } catch (error) {
19
+ logger.error('Bodies取得エラー', { error: error.message });
20
+ res.status(500).json({ success: false, error: error.message });
21
+ }
22
+ });
23
+
24
+ router.post('/bodies', async (req, res) => {
25
+ try {
26
+ const { name, type, ...options } = req.body;
27
+ const result = await taskManager.proposeBody(name, type, options);
28
+ res.status(201).json({
29
+ success: true,
30
+ message: result,
31
+ data: { name, type, ...options }
32
+ });
33
+ } catch (error) {
34
+ return handleRestError(error, res);
35
+ }
36
+ });
37
+
38
+ router.get('/bodies/:name', async (req, res) => {
39
+ try {
40
+ const { name } = req.params;
41
+ const body = taskManager.findBodyByName(name);
42
+ if (!body) {
43
+ return res.status(404).json({
44
+ success: false,
45
+ error: `立体 ${name} が見つかりません`
46
+ });
47
+ }
48
+ res.json({ success: true, data: body });
49
+ } catch (error) {
50
+ logger.error('Body取得エラー', { error: error.message });
51
+ res.status(500).json({ success: false, error: error.message });
52
+ }
53
+ });
54
+ router.delete('/bodies/:name', async (req, res) => {
55
+ try {
56
+ const { name } = req.params;
57
+ const result = await taskManager.deleteBody(name);
58
+ res.json({
59
+ success: true,
60
+ message: result
61
+ });
62
+ } catch (error) {
63
+ return handleRestError(error, res);
64
+ }
65
+ });
66
+
67
+ // Zones endpoints
68
+ router.get('/zones', async (req, res) => {
69
+ try {
70
+ const zones = taskManager.data.zone || [];
71
+ res.json({
72
+ success: true,
73
+ data: zones,
74
+ count: zones.length
75
+ });
76
+ } catch (error) {
77
+ logger.error('Zones取得エラー', { error: error.message });
78
+ res.status(500).json({ success: false, error: error.message });
79
+ }
80
+ });
81
+
82
+ router.post('/zones', async (req, res) => {
83
+ try {
84
+ const { body_name, material, density } = req.body;
85
+ const result = await taskManager.proposeZone(body_name, material, density);
86
+ res.status(201).json({
87
+ success: true,
88
+ message: result,
89
+ data: { body_name, material, density }
90
+ });
91
+ } catch (error) {
92
+ return handleRestError(error, res);
93
+ }
94
+ });
95
+
96
+ router.delete('/zones/:bodyName', async (req, res) => {
97
+ try {
98
+ const { bodyName } = req.params;
99
+ const result = await taskManager.deleteZone(bodyName);
100
+ res.json({
101
+ success: true,
102
+ message: result
103
+ });
104
+ } catch (error) {
105
+ return handleRestError(error, res);
106
+ }
107
+ });
108
+ // Changes endpoints
109
+ router.get('/changes', async (req, res) => {
110
+ try {
111
+ const changes = taskManager.pendingChanges;
112
+ res.json({
113
+ success: true,
114
+ data: changes,
115
+ count: changes.length
116
+ });
117
+ } catch (error) {
118
+ logger.error('Changes取得エラー', { error: error.message });
119
+ res.status(500).json({ success: false, error: error.message });
120
+ }
121
+ });
122
+
123
+ router.post('/changes/apply', async (req, res) => {
124
+ try {
125
+ const result = await taskManager.applyChanges();
126
+ res.json({
127
+ success: true,
128
+ message: result
129
+ });
130
+ } catch (error) {
131
+ return handleRestError(error, res);
132
+ }
133
+ });
134
+
135
+ // Status endpoint
136
+ router.get('/status', (req, res) => {
137
+ res.json({
138
+ success: true,
139
+ data: {
140
+ version: '1.0.0',
141
+ status: 'running',
142
+ bodies_count: taskManager.data.body?.length || 0,
143
+ zones_count: taskManager.data.zone?.length || 0,
144
+ pending_changes: taskManager.pendingChanges.length,
145
+ uptime: process.uptime()
146
+ }
147
+ });
148
+ });
149
+
150
+ return router;
151
+ }
152
+
153
+ function handleRestError(error, res) {
154
+ if (error instanceof ValidationError) {
155
+ return res.status(400).json({
156
+ success: false,
157
+ error: error.message,
158
+ field: error.field,
159
+ value: error.value
160
+ });
161
+ }
162
+
163
+ if (error instanceof PhysicsError) {
164
+ return res.status(422).json({
165
+ success: false,
166
+ error: error.message,
167
+ type: error.code
168
+ });
169
+ }
170
+
171
+ if (error instanceof DataError) {
172
+ return res.status(500).json({
173
+ success: false,
174
+ error: error.message,
175
+ operation: error.operation
176
+ });
177
+ }
178
+
179
+ logger.error('REST APIエラー', { error: error.message });
180
+ return res.status(500).json({
181
+ success: false,
182
+ error: 'サーバー内部エラー'
183
+ });
184
+ }