@tiangong-lca/mcp-server 0.0.19 → 0.0.21

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.
@@ -1,7 +1,6 @@
1
1
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
2
  import { regOpenLcaPrompts } from '../prompts/lca_calculation.js';
3
3
  import { regOpenLcaResources } from '../resources/lca_calculation.js';
4
- import { regBomCalculationTool } from '../tools/bom_calculation.js';
5
4
  import { regFlowSearchTool } from '../tools/flow_hybrid_search.js';
6
5
  import { regLcaCalculationGuidanceTool } from '../tools/lca_calculation_guidance.js';
7
6
  import { regLifecycleModelSearchTool } from '../tools/life_cycle_model_hybrid_search.js';
@@ -17,7 +16,6 @@ export function initializeServer(bearerKey) {
17
16
  regFlowSearchTool(server, bearerKey);
18
17
  regProcessSearchTool(server, bearerKey);
19
18
  regLifecycleModelSearchTool(server, bearerKey);
20
- regBomCalculationTool(server);
21
19
  regOpenLcaLciaTool(server);
22
20
  regOpenLcaListProductSystemsTool(server);
23
21
  regOpenLcaListLCIAMethodsTool(server);
@@ -1,5 +1,4 @@
1
1
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
- import { regBomCalculationTool } from '../tools/bom_calculation.js';
3
2
  import { regCrudTool } from '../tools/db_crud.js';
4
3
  import { regFlowSearchTool } from '../tools/flow_hybrid_search.js';
5
4
  import { regLifecycleModelSearchTool } from '../tools/life_cycle_model_hybrid_search.js';
@@ -12,7 +11,6 @@ export function initializeServer(bearerKey, supabaseSession) {
12
11
  regFlowSearchTool(server, bearerKey);
13
12
  regProcessSearchTool(server, bearerKey);
14
13
  regLifecycleModelSearchTool(server, bearerKey);
15
- regBomCalculationTool(server);
16
14
  regCrudTool(server, supabaseSession ?? bearerKey);
17
15
  return server;
18
16
  }
@@ -4,6 +4,7 @@ import { regOpenLcaResources } from '../resources/lca_calculation.js';
4
4
  import { regOpenLcaLciaTool } from '../tools/openlca_ipc_lcia.js';
5
5
  import { regOpenLcaListLCIAMethodsTool } from '../tools/openlca_ipc_lcia_methods_list.js';
6
6
  import { regOpenLcaListProductSystemsTool } from '../tools/openlca_ipc_process_list.js';
7
+ import { regTidasValidationTool } from '../tools/tidas_data_validation.js';
7
8
  export function initializeServer() {
8
9
  const server = new McpServer({
9
10
  name: 'TianGong-LCA-MCP-Server',
@@ -12,6 +13,7 @@ export function initializeServer() {
12
13
  regOpenLcaLciaTool(server);
13
14
  regOpenLcaListLCIAMethodsTool(server);
14
15
  regOpenLcaListProductSystemsTool(server);
16
+ regTidasValidationTool(server);
15
17
  regOpenLcaPrompts(server);
16
18
  regOpenLcaResources(server);
17
19
  return server;
@@ -30,7 +30,7 @@ async function searchFlows({ query }, bearerKey) {
30
30
  }
31
31
  }
32
32
  export function regFlowSearchTool(server, bearerKey) {
33
- server.tool('Search_flows_Tool', 'Search LCA flows data.', input_schema, async ({ query }) => {
33
+ server.tool('Search_Flows_Tool', 'Search LCA flows data.', input_schema, async ({ query }) => {
34
34
  const result = await searchFlows({
35
35
  query,
36
36
  }, bearerKey);
@@ -30,7 +30,7 @@ async function searchLifecycleModels({ query }, bearerKey) {
30
30
  }
31
31
  }
32
32
  export function regLifecycleModelSearchTool(server, bearerKey) {
33
- server.tool('Search_life_cycle_models_Tool', 'Search LCA life cycle models data.', input_schema, async ({ query }) => {
33
+ server.tool('Search_Life_Cycle_Models_Tool', 'Search LCA life cycle models data.', input_schema, async ({ query }) => {
34
34
  const result = await searchLifecycleModels({
35
35
  query,
36
36
  }, bearerKey);
@@ -30,7 +30,7 @@ async function searchProcesses({ query }, bearerKey) {
30
30
  }
31
31
  }
32
32
  export function regProcessSearchTool(server, bearerKey) {
33
- server.tool('Search_processes_Tool', 'Search LCA processes data.', input_schema, async ({ query }) => {
33
+ server.tool('Search_Processes_Tool', 'Search LCA processes data.', input_schema, async ({ query }) => {
34
34
  const result = await searchProcesses({
35
35
  query,
36
36
  }, bearerKey);
@@ -0,0 +1,207 @@
1
+ import { createContact, createFlow, createFlowProperty, createLCIAMethod, createLifeCycleModel, createProcess, createSource, createUnitGroup, } from '@tiangong-lca/tidas-sdk/core';
2
+ import { z } from 'zod';
3
+ const ENTITY_TYPES = [
4
+ 'contact',
5
+ 'flow',
6
+ 'process',
7
+ 'source',
8
+ 'flowProperty',
9
+ 'unitGroup',
10
+ 'lciaMethod',
11
+ 'lifeCycleModel',
12
+ ];
13
+ const ENTITY_METADATA = {
14
+ contact: {
15
+ name: 'Contact',
16
+ description: 'Contact information data',
17
+ },
18
+ flow: {
19
+ name: 'Flow',
20
+ description: 'Flow data (material/energy flows)',
21
+ },
22
+ process: {
23
+ name: 'Process',
24
+ description: 'Process data',
25
+ },
26
+ source: {
27
+ name: 'Source',
28
+ description: 'Data source information',
29
+ },
30
+ flowProperty: {
31
+ name: 'FlowProperty',
32
+ description: 'Flow property data',
33
+ },
34
+ unitGroup: {
35
+ name: 'UnitGroup',
36
+ description: 'Unit group data',
37
+ },
38
+ lciaMethod: {
39
+ name: 'LCIAMethod',
40
+ description: 'Life Cycle Impact Assessment method data',
41
+ },
42
+ lifeCycleModel: {
43
+ name: 'LifeCycleModel',
44
+ description: 'Life cycle model data',
45
+ },
46
+ };
47
+ const jsonValueSchema = z.lazy(() => z.union([
48
+ z.string(),
49
+ z.number(),
50
+ z.boolean(),
51
+ z.null(),
52
+ z.array(jsonValueSchema),
53
+ z.record(jsonValueSchema),
54
+ ]));
55
+ function validateTidasData(entityType, data) {
56
+ try {
57
+ let validationResult;
58
+ switch (entityType) {
59
+ case 'contact': {
60
+ const entity = createContact(data, { mode: 'strict' });
61
+ validationResult = entity.validate();
62
+ break;
63
+ }
64
+ case 'flow': {
65
+ const entity = createFlow(data, { mode: 'strict' });
66
+ validationResult = entity.validate();
67
+ break;
68
+ }
69
+ case 'process': {
70
+ const entity = createProcess(data, { mode: 'strict' });
71
+ validationResult = entity.validate();
72
+ break;
73
+ }
74
+ case 'source': {
75
+ const entity = createSource(data, { mode: 'strict' });
76
+ validationResult = entity.validate();
77
+ break;
78
+ }
79
+ case 'flowProperty': {
80
+ const entity = createFlowProperty(data, { mode: 'strict' });
81
+ validationResult = entity.validate();
82
+ break;
83
+ }
84
+ case 'unitGroup': {
85
+ const entity = createUnitGroup(data, { mode: 'strict' });
86
+ validationResult = entity.validate();
87
+ break;
88
+ }
89
+ case 'lciaMethod': {
90
+ const entity = createLCIAMethod(data, { mode: 'strict' });
91
+ validationResult = entity.validate();
92
+ break;
93
+ }
94
+ case 'lifeCycleModel': {
95
+ const entity = createLifeCycleModel(data, { mode: 'strict' });
96
+ validationResult = entity.validate();
97
+ break;
98
+ }
99
+ default: {
100
+ const exhaustiveCheck = entityType;
101
+ throw new Error(`Unsupported entity type: ${entityType}`);
102
+ }
103
+ }
104
+ if (validationResult.success) {
105
+ return {
106
+ success: true,
107
+ message: `✓ Validation passed for ${ENTITY_METADATA[entityType].name}`,
108
+ };
109
+ }
110
+ else {
111
+ const errorDetails = validationResult.error?.issues
112
+ ? JSON.stringify(validationResult.error.issues, null, 2)
113
+ : JSON.stringify(validationResult.error);
114
+ return {
115
+ success: false,
116
+ error: validationResult.error,
117
+ message: `✗ Validation failed for ${ENTITY_METADATA[entityType].name}`,
118
+ };
119
+ }
120
+ }
121
+ catch (error) {
122
+ if (error instanceof Error) {
123
+ return {
124
+ success: false,
125
+ error: error,
126
+ message: `✗ Error validating ${ENTITY_METADATA[entityType].name}: ${error.message}`,
127
+ };
128
+ }
129
+ return {
130
+ success: false,
131
+ error: error,
132
+ message: `✗ Unknown error occurred during validation`,
133
+ };
134
+ }
135
+ }
136
+ export function regTidasValidationTool(server) {
137
+ const entityTypeList = ENTITY_TYPES.map((type) => ` - ${type}: ${ENTITY_METADATA[type].name} - ${ENTITY_METADATA[type].description}`).join('\n');
138
+ server.tool('tidas_validate_data', `Validate LCA data against Tidas SDK schemas.
139
+
140
+ Supported entity types (8 types):
141
+ ${entityTypeList}
142
+
143
+ This tool validates data structure and required fields according to ILCD/TIDAS standards.
144
+ Use strict validation mode to ensure data integrity before database operations.`, {
145
+ entityType: z
146
+ .enum(ENTITY_TYPES)
147
+ .describe(`Type of entity to validate. Must be one of: ${ENTITY_TYPES.join(', ')}. Each type corresponds to a specific LCA data structure.`),
148
+ data: jsonValueSchema.describe('The JSON data to validate. Should be a complete entity object matching the specified entityType structure according to ILCD/TIDAS format.'),
149
+ }, async ({ entityType, data }) => {
150
+ try {
151
+ const result = validateTidasData(entityType, data);
152
+ if (result.success) {
153
+ return {
154
+ content: [
155
+ {
156
+ type: 'text',
157
+ text: `${result.message}
158
+
159
+ Entity Type: ${ENTITY_METADATA[entityType].name}
160
+ Status: ✓ Valid
161
+ Description: ${ENTITY_METADATA[entityType].description}
162
+
163
+ The data conforms to the ${ENTITY_METADATA[entityType].name} schema and can be safely used for database operations.`,
164
+ },
165
+ ],
166
+ };
167
+ }
168
+ else {
169
+ const errorDetails = result.error?.issues
170
+ ? JSON.stringify(result.error.issues, null, 2)
171
+ : result.error
172
+ ? JSON.stringify(result.error, null, 2)
173
+ : 'Unknown validation error';
174
+ return {
175
+ content: [
176
+ {
177
+ type: 'text',
178
+ text: `${result.message}
179
+
180
+ Entity Type: ${ENTITY_METADATA[entityType].name}
181
+ Status: ✗ Invalid
182
+ Description: ${ENTITY_METADATA[entityType].description}
183
+
184
+ Validation Errors:
185
+ ${errorDetails}
186
+
187
+ Please fix the validation errors before attempting database operations.`,
188
+ },
189
+ ],
190
+ isError: true,
191
+ };
192
+ }
193
+ }
194
+ catch (error) {
195
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
196
+ return {
197
+ content: [
198
+ {
199
+ type: 'text',
200
+ text: `Failed to validate data: ${errorMessage}`,
201
+ },
202
+ ],
203
+ isError: true,
204
+ };
205
+ }
206
+ });
207
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tiangong-lca/mcp-server",
3
- "version": "0.0.19",
3
+ "version": "0.0.21",
4
4
  "description": "TianGong LCA MCP Server",
5
5
  "license": "MIT",
6
6
  "author": "Nan LI",
@@ -22,6 +22,7 @@
22
22
  "start": "npm run build && npx dotenv -e .env -- npx @modelcontextprotocol/inspector node dist/src/index.js",
23
23
  "start:server": "npm run build && concurrently \"npx dotenv -e .env -- node dist/src/index_server.js\" \"DANGEROUSLY_OMIT_AUTH=true npx @modelcontextprotocol/inspector\"",
24
24
  "start:server-local": "npm run build && concurrently \"npx dotenv -e .env -- node dist/src/index_server_local.js\" \"DANGEROUSLY_OMIT_AUTH=true npx @modelcontextprotocol/inspector\"",
25
+ "test": "node test/tidas_validation_test.js",
25
26
  "lint": "prettier -c --write \"**/**.{js,jsx,tsx,ts,less,md,json}\"",
26
27
  "ncu": "npx npm-check-updates",
27
28
  "ncu:update": "npx npm-check-updates -u"
@@ -1,30 +0,0 @@
1
- import { z } from 'zod';
2
- const input_schema = {
3
- a: z.number().min(1).describe('The first number'),
4
- b: z.number().min(1).describe('The second number'),
5
- };
6
- async function calculation({ a, b }) {
7
- try {
8
- return a + b;
9
- }
10
- catch (error) {
11
- console.error('Error making the request:', error);
12
- throw error;
13
- }
14
- }
15
- export function regBomCalculationTool(server) {
16
- server.tool('BOM_Calculation', 'Calculate sum of two numbers.', input_schema, async ({ a, b }) => {
17
- const result = await calculation({
18
- a,
19
- b,
20
- });
21
- return {
22
- content: [
23
- {
24
- type: 'text',
25
- text: result.toString(),
26
- },
27
- ],
28
- };
29
- });
30
- }