@tiangong-lca/mcp-server 0.0.20 → 0.0.22
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.
- package/dist/src/_shared/init_server.js +2 -4
- package/dist/src/_shared/init_server_http.js +0 -2
- package/dist/src/_shared/init_server_http_local.js +4 -2
- package/dist/src/prompts/lca_calculation.js +1 -1
- package/dist/src/resources/lca_calculation.js +1 -1
- package/dist/src/tools/flow_hybrid_search.js +1 -1
- package/dist/src/tools/lca_calculation_guidance.js +1 -1
- package/dist/src/tools/life_cycle_model_hybrid_search.js +1 -1
- package/dist/src/tools/{openlca_ipc_process_list.js → openlca_ipc_system_processes_list.js} +9 -8
- package/dist/src/tools/process_hybrid_search.js +1 -1
- package/dist/src/tools/tidas_data_validation.js +207 -0
- package/package.json +2 -1
- package/dist/src/tools/bom_calculation.js +0 -30
|
@@ -1,13 +1,12 @@
|
|
|
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';
|
|
8
7
|
import { regOpenLcaLciaTool } from '../tools/openlca_ipc_lcia.js';
|
|
9
8
|
import { regOpenLcaListLCIAMethodsTool } from '../tools/openlca_ipc_lcia_methods_list.js';
|
|
10
|
-
import {
|
|
9
|
+
import { regOpenLcaListSystemProcessesTool } from '../tools/openlca_ipc_system_processes_list.js';
|
|
11
10
|
import { regProcessSearchTool } from '../tools/process_hybrid_search.js';
|
|
12
11
|
export function initializeServer(bearerKey) {
|
|
13
12
|
const server = new McpServer({
|
|
@@ -17,9 +16,8 @@ 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
|
+
regOpenLcaListSystemProcessesTool(server);
|
|
23
21
|
regOpenLcaListLCIAMethodsTool(server);
|
|
24
22
|
regOpenLcaPrompts(server);
|
|
25
23
|
regOpenLcaResources(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
|
}
|
|
@@ -3,7 +3,8 @@ import { regOpenLcaPrompts } from '../prompts/lca_calculation.js';
|
|
|
3
3
|
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
|
-
import {
|
|
6
|
+
import { regOpenLcaListSystemProcessesTool } from '../tools/openlca_ipc_system_processes_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',
|
|
@@ -11,7 +12,8 @@ export function initializeServer() {
|
|
|
11
12
|
});
|
|
12
13
|
regOpenLcaLciaTool(server);
|
|
13
14
|
regOpenLcaListLCIAMethodsTool(server);
|
|
14
|
-
|
|
15
|
+
regOpenLcaListSystemProcessesTool(server);
|
|
16
|
+
regTidasValidationTool(server);
|
|
15
17
|
regOpenLcaPrompts(server);
|
|
16
18
|
regOpenLcaResources(server);
|
|
17
19
|
return server;
|
|
@@ -9,7 +9,7 @@ export function regOpenLcaPrompts(server) {
|
|
|
9
9
|
text: `I am an expert in Life Cycle Assessment (LCA) and use the MCP tool to perform LCA calculations.
|
|
10
10
|
The workflow is as follows:
|
|
11
11
|
1. Use the OpenLCA_Impact_Assessment_Tool to list all LCIA (Life Cycle Impact Assessment) method UUIDs and their corresponding names.
|
|
12
|
-
2. Use the
|
|
12
|
+
2. Use the OpenLCA_List_System_Processes_Tool to list all system process UUIDs and their corresponding names.
|
|
13
13
|
3. Use the OpenLCA_Impact_Assessment_Tool to perform LCA calculations.`,
|
|
14
14
|
},
|
|
15
15
|
},
|
|
@@ -7,7 +7,7 @@ export function regOpenLcaResources(server) {
|
|
|
7
7
|
mimeType: 'text/plain',
|
|
8
8
|
text: `The workflow to perform LCA calculations using the MCP tool is as follows:
|
|
9
9
|
1. Use the OpenLCA_Impact_Assessment_Tool to list all LCIA (Life Cycle Impact Assessment) method UUIDs and their corresponding names.
|
|
10
|
-
2. Use the
|
|
10
|
+
2. Use the OpenLCA_List_System_Processes_Tool to list all system process UUIDs and their corresponding names.
|
|
11
11
|
3. Use the OpenLCA_Impact_Assessment_Tool to perform LCA calculations.`,
|
|
12
12
|
},
|
|
13
13
|
],
|
|
@@ -30,7 +30,7 @@ async function searchFlows({ query }, bearerKey) {
|
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
export function regFlowSearchTool(server, bearerKey) {
|
|
33
|
-
server.tool('
|
|
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);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
async function getLcaCalculationGuidance() {
|
|
2
2
|
const prompt = `The workflow to perform LCA calculations using the MCP tool is as follows:
|
|
3
3
|
1. Use the OpenLCA_Impact_Assessment_Tool to list all LCIA (Life Cycle Impact Assessment) method UUIDs and their corresponding names.
|
|
4
|
-
2. Use the
|
|
4
|
+
2. Use the OpenLCA_List_System_Processes_Tool to list all system process UUIDs and their corresponding names.
|
|
5
5
|
3. Use the OpenLCA_Impact_Assessment_Tool to perform LCA calculations.`;
|
|
6
6
|
return prompt;
|
|
7
7
|
}
|
|
@@ -30,7 +30,7 @@ async function searchLifecycleModels({ query }, bearerKey) {
|
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
export function regLifecycleModelSearchTool(server, bearerKey) {
|
|
33
|
-
server.tool('
|
|
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);
|
|
@@ -3,13 +3,14 @@ import { z } from 'zod';
|
|
|
3
3
|
const input_schema = {
|
|
4
4
|
serverUrl: z.string().default('http://localhost:8080').describe('OpenLCA IPC server URL'),
|
|
5
5
|
};
|
|
6
|
-
async function
|
|
6
|
+
async function listSystemProcesses({ serverUrl = 'http://localhost:8080', }) {
|
|
7
7
|
const client = o.IpcClient.on(serverUrl);
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
const processes = await client.getDescriptors(o.RefType.Process);
|
|
9
|
+
const systemProcesses = processes.filter((proc) => proc.processType === o.ProcessType.LCI_RESULT);
|
|
10
|
+
if (systemProcesses.length === 0) {
|
|
11
|
+
throw new Error('No system processes found');
|
|
11
12
|
}
|
|
12
|
-
const resultsObj =
|
|
13
|
+
const resultsObj = systemProcesses.map((sys) => {
|
|
13
14
|
const result = {
|
|
14
15
|
id: sys.id,
|
|
15
16
|
category: sys.category,
|
|
@@ -30,9 +31,9 @@ async function listProductSystems({ serverUrl = 'http://localhost:8080', }) {
|
|
|
30
31
|
});
|
|
31
32
|
return JSON.stringify(resultsObj);
|
|
32
33
|
}
|
|
33
|
-
export function
|
|
34
|
-
server.tool('
|
|
35
|
-
const result = await
|
|
34
|
+
export function regOpenLcaListSystemProcessesTool(server) {
|
|
35
|
+
server.tool('OpenLCA_List_System_Processes_Tool', 'List all system processes using OpenLCA.', input_schema, async ({ serverUrl }) => {
|
|
36
|
+
const result = await listSystemProcesses({
|
|
36
37
|
serverUrl: serverUrl,
|
|
37
38
|
});
|
|
38
39
|
return {
|
|
@@ -30,7 +30,7 @@ async function searchProcesses({ query }, bearerKey) {
|
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
export function regProcessSearchTool(server, bearerKey) {
|
|
33
|
-
server.tool('
|
|
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_Data_Validate_Tool', `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.
|
|
3
|
+
"version": "0.0.22",
|
|
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
|
-
}
|