@tiangong-lca/mcp-server 0.0.3 → 0.0.5

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/README.md CHANGED
@@ -1,21 +1,21 @@
1
- # TianGong-LCA-MCP
1
+ # TianGong-AI-MCP
2
2
 
3
- [中文](./README.md) | [English](./README_EN.md)
3
+ [中文](https://github.com/linancn/tiangong-lca-mcp/blob/main/README_CN.md) | [English](https://github.com/linancn/tiangong-lca-mcp/blob/main/README.md)
4
4
 
5
- TianGong LCA Model Context Protocol (MCP) Server 支持 STDIO SSE StreamableHttp 三种协议。
5
+ TianGong AI Model Context Protocol (MCP) Server supports STDIO, SSE and StreamableHttp protocols.
6
6
 
7
- ## 启动 MCP 服务器
7
+ ## Starting MCP Server
8
8
 
9
- ### 客户端 STDIO 服务器
9
+ ### Client STDIO Server
10
10
 
11
11
  ```bash
12
12
  npm install -g @tiangong-lca/mcp-server
13
13
 
14
14
  npx dotenv -e .env -- \
15
- npx @tiangong-lca/mcp-server
15
+ npx -p @tiangong-lca/mcp-server tiangong-lca-mcp-stdio
16
16
  ```
17
17
 
18
- ### 远程 SSE 服务器
18
+ ### Remote SSE Server
19
19
 
20
20
  ```bash
21
21
  npm install -g @tiangong-lca/mcp-server
@@ -28,63 +28,66 @@ npx -y supergateway \
28
28
  --ssePath /sse --messagePath /message
29
29
  ```
30
30
 
31
- ### 使用 Docker
31
+ ### Using Docker
32
32
 
33
33
  ```bash
34
- # 使用 Dockerfile 构建 MCP 服务器镜像(可选)
34
+ # Build MCP server image using Dockerfile (optional)
35
35
  docker build -t linancn/tiangong-lca-mcp-server:0.0.1 .
36
36
 
37
- # 拉取 MCP 服务器镜像
37
+ # Pull MCP server image
38
38
  docker pull linancn/tiangong-lca-mcp-server:0.0.1
39
39
 
40
- # 使用 Docker 启动 MCP 服务器
40
+ # Start MCP server using Docker
41
41
  docker run -d \
42
42
  --name tiangong-lca-mcp-server \
43
- --publish 3001:80 \
43
+ --publish 9278:9278 \
44
44
  --env-file .env \
45
45
  linancn/tiangong-lca-mcp-server:0.0.1
46
46
  ```
47
47
 
48
- ## 开发
48
+ ## Development
49
49
 
50
- ### 环境设置
50
+ ### Environment Setup
51
51
 
52
52
  ```bash
53
- # 安装 Node.js
53
+ # Install Node.js
54
54
  curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.2/install.sh | bash
55
55
  nvm install 22
56
56
  nvm use
57
57
 
58
- # 安装依赖
58
+ # Install dependencies
59
59
  npm install
60
60
 
61
- # 更新依赖
61
+ # Update dependencies
62
62
  npm update && npm ci
63
63
  ```
64
64
 
65
- ### 代码格式化
65
+ ### Code Formatting
66
66
 
67
67
  ```bash
68
- # 使用代码检查工具格式化代码
68
+ # Format code using the linter
69
69
  npm run lint
70
70
  ```
71
71
 
72
- ### 本地测试
72
+ ### Local Testing
73
73
 
74
- #### STDIO 服务器
74
+ #### STDIO Server
75
75
 
76
76
  ```bash
77
- # 使用 MCP Inspector 启动 STDIO 服务器
77
+ # Launch the STDIO Server using MCP Inspector
78
78
  npm start
79
79
  ```
80
80
 
81
- #### SSE 服务器
81
+ #### SSE Server
82
82
 
83
83
  ```bash
84
- # 打包当前项目
84
+ # Build and package the project
85
85
  npm run build && npm pack
86
86
 
87
- # 启动 SSE 服务器,如配置了参数 --baseUrl ,应设置为有效的 IP 地址或域名
87
+ # Optionally, install supergateway globally
88
+ npm install -g supergateway
89
+
90
+ # Launch the SSE Server (If the parameter --baseUrl is configured, it should be set to a valid IP address or domain name)
88
91
  npx dotenv -e .env -- \
89
92
  npx -y supergateway \
90
93
  --stdio "npx -y -p tiangong-lca-mcp-server-0.0.3.tgz tiangong-lca-mcp-stdio" \
@@ -92,14 +95,20 @@ npx -y supergateway \
92
95
  --ssePath /sse \
93
96
  --messagePath /message
94
97
 
95
- # 启动 MCP Inspector
98
+ # Launch MCP Inspector
96
99
  npx @modelcontextprotocol/inspector
97
100
  ```
98
101
 
99
- ### 发布
102
+ ### Publishing
100
103
 
101
104
  ```bash
102
105
  npm login
103
106
 
104
107
  npm run build && npm publish
105
108
  ```
109
+
110
+ ### scaffold
111
+
112
+ ```bash
113
+ npx tsx src/tools/openlca_ipc_test.ts
114
+ ```
@@ -1,7 +1,10 @@
1
1
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import { regBomCalculationTool } from '../tools/bom_calculation.js';
2
3
  import { regFlowSearchTool } from '../tools/flow_hybrid_search.js';
4
+ import { regOpenLcaLciaTool } from '../tools/openlca_ipc_lcia.js';
5
+ import { regOpenLcaListLCIAMethodsTool } from '../tools/openlca_ipc_lcia_methods_list.js';
6
+ import { regOpenLcaListSystemProcessTool } from '../tools/openlca_ipc_process_list.js';
3
7
  import { regProcessSearchTool } from '../tools/process_hybrid_search.js';
4
- import { regBomCalculationTool } from '../tools/bom_calculation.js';
5
8
  export function initializeServer() {
6
9
  const server = new McpServer({
7
10
  name: 'TianGong-MCP-Server',
@@ -10,6 +13,9 @@ export function initializeServer() {
10
13
  regFlowSearchTool(server);
11
14
  regProcessSearchTool(server);
12
15
  regBomCalculationTool(server);
16
+ regOpenLcaLciaTool(server);
17
+ regOpenLcaListSystemProcessTool(server);
18
+ regOpenLcaListLCIAMethodsTool(server);
13
19
  return server;
14
20
  }
15
21
  export function getServer() {
@@ -2,9 +2,41 @@
2
2
  import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
3
3
  import express from 'express';
4
4
  import { getServer } from './_shared/init_server.js';
5
+ const BEARER_KEY = process.env.BEARER_KEY;
6
+ const authenticateBearer = (req, res, next) => {
7
+ if (!BEARER_KEY) {
8
+ next();
9
+ return;
10
+ }
11
+ const authHeader = req.headers.authorization;
12
+ if (!authHeader || !authHeader.startsWith('Bearer ')) {
13
+ res.status(401).json({
14
+ jsonrpc: '2.0',
15
+ error: {
16
+ code: -32001,
17
+ message: 'Missing or invalid authorization header',
18
+ },
19
+ id: null,
20
+ });
21
+ return;
22
+ }
23
+ const token = authHeader.substring(7);
24
+ if (token !== BEARER_KEY) {
25
+ res.status(403).json({
26
+ jsonrpc: '2.0',
27
+ error: {
28
+ code: -32002,
29
+ message: 'Invalid bearer token',
30
+ },
31
+ id: null,
32
+ });
33
+ return;
34
+ }
35
+ next();
36
+ };
5
37
  const app = express();
6
38
  app.use(express.json());
7
- app.post('/mcp', async (req, res) => {
39
+ app.post('/mcp', authenticateBearer, async (req, res) => {
8
40
  try {
9
41
  const server = getServer();
10
42
  const transport = new StreamableHTTPServerTransport({
@@ -15,7 +15,8 @@ async function calculation({ a, b }) {
15
15
  export function regBomCalculationTool(server) {
16
16
  server.tool('BOM_Calculation', 'Calculate sum of two numbers.', input_schema, async ({ a, b }) => {
17
17
  const result = await calculation({
18
- a, b,
18
+ a,
19
+ b,
19
20
  });
20
21
  return {
21
22
  content: [
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,57 @@
1
+ import * as o from 'olca-ipc';
2
+ import { z } from 'zod';
3
+ const input_schema = {
4
+ systemProcess: z.string().min(1).describe('OpenLCA product system ID'),
5
+ impactMethod: z.string().min(1).describe('OpenLCA impact method ID'),
6
+ serverUrl: z.string().default('http://localhost:8080').describe('OpenLCA IPC server URL'),
7
+ };
8
+ async function calculateLcaImpacts({ systemProcess, impactMethod, serverUrl = 'http://localhost:8080', }) {
9
+ if (!systemProcess) {
10
+ throw new Error('No systemProcess provided');
11
+ }
12
+ if (!impactMethod) {
13
+ throw new Error('No impactMethod provided');
14
+ }
15
+ const client = o.IpcClient.on(serverUrl);
16
+ const selectedSystemProcess = await client.get(o.RefType.ProductSystem, systemProcess);
17
+ if (!selectedSystemProcess)
18
+ throw new Error('Product system not found');
19
+ const selectedMethod = await client.get(o.RefType.ImpactMethod, impactMethod);
20
+ if (!selectedMethod)
21
+ throw new Error('Impact method not found');
22
+ console.log('Calculating LCA impacts...');
23
+ const setup = o.CalculationSetup.of({
24
+ target: selectedSystemProcess,
25
+ impactMethod: selectedMethod,
26
+ });
27
+ const result = await client.calculate(setup);
28
+ const state = await result.untilReady();
29
+ if (state.error) {
30
+ throw new Error(`Calculation failed: ${state.error}`);
31
+ }
32
+ const impacts = await result.getTotalImpacts();
33
+ const resultsObj = impacts.map((impact) => ({
34
+ name: impact.impactCategory?.name,
35
+ value: impact.amount,
36
+ unit: impact.impactCategory?.refUnit,
37
+ }));
38
+ result.dispose();
39
+ return JSON.stringify(resultsObj);
40
+ }
41
+ export function regOpenLcaTool(server) {
42
+ server.tool('OpenLCA_Impact_Assessment_Tool', 'Calculate life cycle impact assessment using OpenLCA.', input_schema, async ({ systemProcess, impactMethod, serverUrl }) => {
43
+ const result = await calculateLcaImpacts({
44
+ systemProcess: systemProcess,
45
+ impactMethod: impactMethod,
46
+ serverUrl: serverUrl,
47
+ });
48
+ return {
49
+ content: [
50
+ {
51
+ type: 'text',
52
+ text: result,
53
+ },
54
+ ],
55
+ };
56
+ });
57
+ }
@@ -0,0 +1,57 @@
1
+ import * as o from 'olca-ipc';
2
+ import { z } from 'zod';
3
+ const input_schema = {
4
+ systemProcess: z.string().min(1).describe('OpenLCA product system ID'),
5
+ impactMethod: z.string().min(1).describe('OpenLCA impact method ID'),
6
+ serverUrl: z.string().default('http://localhost:8080').describe('OpenLCA IPC server URL'),
7
+ };
8
+ async function calculateLcaImpacts({ systemProcess, impactMethod, serverUrl = 'http://localhost:8080', }) {
9
+ if (!systemProcess) {
10
+ throw new Error('No systemProcess provided');
11
+ }
12
+ if (!impactMethod) {
13
+ throw new Error('No impactMethod provided');
14
+ }
15
+ const client = o.IpcClient.on(serverUrl);
16
+ const selectedSystemProcess = await client.get(o.RefType.ProductSystem, systemProcess);
17
+ if (!selectedSystemProcess)
18
+ throw new Error('Product system not found');
19
+ const selectedMethod = await client.get(o.RefType.ImpactMethod, impactMethod);
20
+ if (!selectedMethod)
21
+ throw new Error('Impact method not found');
22
+ console.log('Calculating LCA impacts...');
23
+ const setup = o.CalculationSetup.of({
24
+ target: selectedSystemProcess,
25
+ impactMethod: selectedMethod,
26
+ });
27
+ const result = await client.calculate(setup);
28
+ const state = await result.untilReady();
29
+ if (state.error) {
30
+ throw new Error(`Calculation failed: ${state.error}`);
31
+ }
32
+ const impacts = await result.getTotalImpacts();
33
+ const resultsObj = impacts.map((impact) => ({
34
+ name: impact.impactCategory?.name,
35
+ value: impact.amount,
36
+ unit: impact.impactCategory?.refUnit,
37
+ }));
38
+ result.dispose();
39
+ return JSON.stringify(resultsObj);
40
+ }
41
+ export function regOpenLcaLciaTool(server) {
42
+ server.tool('OpenLCA_Impact_Assessment_Tool', 'Calculate life cycle impact assessment using OpenLCA.', input_schema, async ({ systemProcess, impactMethod, serverUrl }) => {
43
+ const result = await calculateLcaImpacts({
44
+ systemProcess: systemProcess,
45
+ impactMethod: impactMethod,
46
+ serverUrl: serverUrl,
47
+ });
48
+ return {
49
+ content: [
50
+ {
51
+ type: 'text',
52
+ text: result,
53
+ },
54
+ ],
55
+ };
56
+ });
57
+ }
@@ -0,0 +1,48 @@
1
+ import * as o from 'olca-ipc';
2
+ import { z } from 'zod';
3
+ const input_schema = {
4
+ serverUrl: z.string().default('http://localhost:8080').describe('OpenLCA IPC server URL'),
5
+ };
6
+ async function listLCIAMethods({ serverUrl = 'http://localhost:8080', }) {
7
+ const client = o.IpcClient.on(serverUrl);
8
+ const impactMethods = await client.getDescriptors(o.RefType.ImpactMethod);
9
+ if (impactMethods.length === 0) {
10
+ throw new Error('No LICA methods found');
11
+ }
12
+ console.log(impactMethods);
13
+ const resultsObj = impactMethods.map((sys) => {
14
+ const result = {
15
+ id: sys.id,
16
+ category: sys.category,
17
+ description: sys.description,
18
+ flowType: sys.flowType,
19
+ location: sys.location,
20
+ name: sys.name,
21
+ processType: sys.processType,
22
+ refUnit: sys.refUnit,
23
+ refType: sys.refType,
24
+ };
25
+ Object.keys(result).forEach((key) => {
26
+ if (result[key] === undefined) {
27
+ delete result[key];
28
+ }
29
+ });
30
+ return result;
31
+ });
32
+ return JSON.stringify(resultsObj);
33
+ }
34
+ export function regOpenLcaListLCIAMethodsTool(server) {
35
+ server.tool('OpenLCA_List_LCIA_Methods_Tool', 'List all LCIA methods using OpenLCA.', input_schema, async ({ serverUrl }) => {
36
+ const result = await listLCIAMethods({
37
+ serverUrl: serverUrl,
38
+ });
39
+ return {
40
+ content: [
41
+ {
42
+ type: 'text',
43
+ text: result,
44
+ },
45
+ ],
46
+ };
47
+ });
48
+ }
@@ -0,0 +1,47 @@
1
+ import * as o from 'olca-ipc';
2
+ import { z } from 'zod';
3
+ const input_schema = {
4
+ serverUrl: z.string().default('http://localhost:8080').describe('OpenLCA IPC server URL'),
5
+ };
6
+ async function listSystemProcesses({ serverUrl = 'http://localhost:8080', }) {
7
+ const client = o.IpcClient.on(serverUrl);
8
+ const systemProcesses = await client.getDescriptors(o.RefType.ProductSystem);
9
+ if (systemProcesses.length === 0) {
10
+ throw new Error('No product systems found');
11
+ }
12
+ const resultsObj = systemProcesses.map((sys) => {
13
+ const result = {
14
+ id: sys.id,
15
+ category: sys.category,
16
+ description: sys.description,
17
+ flowType: sys.flowType,
18
+ location: sys.location,
19
+ name: sys.name,
20
+ processType: sys.processType,
21
+ refUnit: sys.refUnit,
22
+ refType: sys.refType,
23
+ };
24
+ Object.keys(result).forEach((key) => {
25
+ if (result[key] === undefined) {
26
+ delete result[key];
27
+ }
28
+ });
29
+ return result;
30
+ });
31
+ return JSON.stringify(resultsObj);
32
+ }
33
+ export function regOpenLcaListSystemProcessTool(server) {
34
+ server.tool('OpenLCA_List_System_Processes_Tool', 'List all system processes using OpenLCA.', input_schema, async ({ serverUrl }) => {
35
+ const result = await listSystemProcesses({
36
+ serverUrl: serverUrl,
37
+ });
38
+ return {
39
+ content: [
40
+ {
41
+ type: 'text',
42
+ text: result,
43
+ },
44
+ ],
45
+ };
46
+ });
47
+ }
@@ -0,0 +1,17 @@
1
+ import * as o from 'olca-ipc';
2
+ async function main() {
3
+ const protocol = 'IPC';
4
+ const client = protocol === 'IPC'
5
+ ? o.IpcClient.on('http://localhost:8080')
6
+ : o.RestClient.on('http://localhost:8080');
7
+ const systems = await client.getDescriptors(o.RefType.ProductSystem);
8
+ if (systems.length === 0) {
9
+ console.log('error: no product systems found');
10
+ return;
11
+ }
12
+ console.log('可用的产品系统:');
13
+ systems.forEach((sys, index) => {
14
+ console.log(`${index}: ${sys.name} (${sys.id})`);
15
+ });
16
+ }
17
+ main();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tiangong-lca/mcp-server",
3
- "version": "0.0.3",
3
+ "version": "0.0.5",
4
4
  "description": "TianGong LCA MCP Server",
5
5
  "license": "MIT",
6
6
  "author": "Nan LI",
@@ -22,18 +22,20 @@
22
22
  "lint": "prettier -c --write \"**/**.{js,jsx,tsx,ts,less,md,json}\""
23
23
  },
24
24
  "dependencies": {
25
+ "olca-ipc": "^2.2.1",
25
26
  "@types/express": "^5.0.2",
26
- "@modelcontextprotocol/sdk": "^1.11.4",
27
- "@supabase/supabase-js": "^2.49.4",
28
- "zod": "^3.24.4"
27
+ "@modelcontextprotocol/sdk": "^1.12.1",
28
+ "@supabase/supabase-js": "^2.49.10",
29
+ "zod": "^3.25.51"
29
30
  },
30
31
  "devDependencies": {
31
- "@modelcontextprotocol/inspector": "^0.12.0",
32
+ "@modelcontextprotocol/inspector": "^0.14.0",
32
33
  "dotenv-cli": "^8.0.0",
33
34
  "prettier": "^3.5.3",
34
35
  "prettier-plugin-organize-imports": "^4.1.0",
35
36
  "shx": "^0.4.0",
36
- "supergateway": "^2.7.0",
37
+ "supergateway": "^3.1.0",
38
+ "tsx": "^4.19.4",
37
39
  "typescript": "^5.8.3"
38
40
  }
39
41
  }