@tiangong-lca/mcp-server 0.0.17 → 0.0.19

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.
@@ -4,6 +4,7 @@ import { regOpenLcaResources } from '../resources/lca_calculation.js';
4
4
  import { regBomCalculationTool } from '../tools/bom_calculation.js';
5
5
  import { regFlowSearchTool } from '../tools/flow_hybrid_search.js';
6
6
  import { regLcaCalculationGuidanceTool } from '../tools/lca_calculation_guidance.js';
7
+ import { regLifecycleModelSearchTool } from '../tools/life_cycle_model_hybrid_search.js';
7
8
  import { regOpenLcaLciaTool } from '../tools/openlca_ipc_lcia.js';
8
9
  import { regOpenLcaListLCIAMethodsTool } from '../tools/openlca_ipc_lcia_methods_list.js';
9
10
  import { regOpenLcaListProductSystemsTool } from '../tools/openlca_ipc_process_list.js';
@@ -15,6 +16,7 @@ export function initializeServer(bearerKey) {
15
16
  }, { capabilities: { prompts: {}, resources: {} } });
16
17
  regFlowSearchTool(server, bearerKey);
17
18
  regProcessSearchTool(server, bearerKey);
19
+ regLifecycleModelSearchTool(server, bearerKey);
18
20
  regBomCalculationTool(server);
19
21
  regOpenLcaLciaTool(server);
20
22
  regOpenLcaListProductSystemsTool(server);
@@ -2,6 +2,7 @@ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
2
  import { regBomCalculationTool } from '../tools/bom_calculation.js';
3
3
  import { regCrudTool } from '../tools/db_crud.js';
4
4
  import { regFlowSearchTool } from '../tools/flow_hybrid_search.js';
5
+ import { regLifecycleModelSearchTool } from '../tools/life_cycle_model_hybrid_search.js';
5
6
  import { regProcessSearchTool } from '../tools/process_hybrid_search.js';
6
7
  export function initializeServer(bearerKey, supabaseSession) {
7
8
  const server = new McpServer({
@@ -10,6 +11,7 @@ export function initializeServer(bearerKey, supabaseSession) {
10
11
  });
11
12
  regFlowSearchTool(server, bearerKey);
12
13
  regProcessSearchTool(server, bearerKey);
14
+ regLifecycleModelSearchTool(server, bearerKey);
13
15
  regBomCalculationTool(server);
14
16
  regCrudTool(server, supabaseSession ?? bearerKey);
15
17
  return server;
@@ -1,5 +1,6 @@
1
1
  import { randomUUID } from 'node:crypto';
2
2
  import { createClient, FunctionRegion } from '@supabase/supabase-js';
3
+ import { createContact, createFlow, createLifeCycleModel, createProcess, createSource, } from '@tiangong-lca/tidas-sdk/core';
3
4
  import { z } from 'zod';
4
5
  import { supabase_base_url, supabase_publishable_key } from '../_shared/config.js';
5
6
  import { resolveSupabaseAccessToken } from '../_shared/supabase_session.js';
@@ -54,7 +55,7 @@ const toolParamsSchema = {
54
55
  .describe('String stored in the `version` column (required for update/delete, optional filter for select).'),
55
56
  filters: filtersSchema
56
57
  .optional()
57
- .describe('Equality filters such as { "name": "Example" } (select only).'),
58
+ .describe('Optional equality filters as JSON object, e.g. { "name": "Example" }. Only used for select operations. Leave empty for insert/update/delete operations.'),
58
59
  jsonOrdered: jsonValueSchema
59
60
  .optional()
60
61
  .describe('JSON value persisted into json_ordered (required for insert/update; omit for select/delete).'),
@@ -128,6 +129,54 @@ function ensureRows(rows, errorMessage) {
128
129
  }
129
130
  return rows;
130
131
  }
132
+ function validateJsonOrdered(table, jsonOrdered) {
133
+ try {
134
+ let validationResult;
135
+ switch (table) {
136
+ case 'contacts': {
137
+ const contact = createContact(jsonOrdered, { mode: 'strict' });
138
+ validationResult = contact.validate();
139
+ break;
140
+ }
141
+ case 'flows': {
142
+ const flow = createFlow(jsonOrdered, { mode: 'strict' });
143
+ validationResult = flow.validate();
144
+ break;
145
+ }
146
+ case 'lifecyclemodels': {
147
+ const lifecycleModel = createLifeCycleModel(jsonOrdered, { mode: 'strict' });
148
+ validationResult = lifecycleModel.validate();
149
+ break;
150
+ }
151
+ case 'processes': {
152
+ const process = createProcess(jsonOrdered, { mode: 'strict' });
153
+ validationResult = process.validate();
154
+ break;
155
+ }
156
+ case 'sources': {
157
+ const source = createSource(jsonOrdered, { mode: 'strict' });
158
+ validationResult = source.validate();
159
+ break;
160
+ }
161
+ default: {
162
+ const exhaustiveCheck = table;
163
+ throw new Error(`Unsupported table type: ${table}`);
164
+ }
165
+ }
166
+ if (!validationResult.success) {
167
+ const errorDetails = validationResult.error?.issues
168
+ ? JSON.stringify(validationResult.error.issues, null, 2)
169
+ : JSON.stringify(validationResult.error);
170
+ throw new Error(`Validation failed for table "${table}". Errors: ${errorDetails}`);
171
+ }
172
+ }
173
+ catch (error) {
174
+ if (error instanceof Error) {
175
+ throw new Error(`Failed to validate jsonOrdered for table "${table}": ${error.message}`);
176
+ }
177
+ throw error;
178
+ }
179
+ }
131
180
  async function createSupabaseClient(bearerKey) {
132
181
  const { session: normalizedSession, accessToken: bearerToken } = resolveSupabaseAccessToken(bearerKey);
133
182
  const supabase = createClient(supabase_base_url, supabase_publishable_key, {
@@ -162,7 +211,9 @@ async function handleSelect(supabase, input) {
162
211
  let queryBuilder = supabase.from(table).select('*');
163
212
  if (filters) {
164
213
  for (const [column, value] of Object.entries(filters)) {
165
- queryBuilder = queryBuilder.eq(column, value);
214
+ if (value !== null && value !== undefined) {
215
+ queryBuilder = queryBuilder.eq(column, value);
216
+ }
166
217
  }
167
218
  }
168
219
  if (id) {
@@ -186,6 +237,7 @@ async function handleInsert(supabase, input) {
186
237
  if (jsonOrdered === undefined) {
187
238
  throw new Error('jsonOrdered is required for insert operations.');
188
239
  }
240
+ validateJsonOrdered(table, jsonOrdered);
189
241
  const newId = randomUUID();
190
242
  const keyColumn = getPrimaryKeyColumn(table);
191
243
  const { data, error } = await supabase
@@ -209,6 +261,7 @@ async function handleUpdate(supabase, accessToken, input) {
209
261
  if (jsonOrdered === undefined) {
210
262
  throw new Error('jsonOrdered is required for update operations.');
211
263
  }
264
+ validateJsonOrdered(table, jsonOrdered);
212
265
  const token = requireAccessToken(accessToken);
213
266
  const { data: functionPayload, error } = await supabase.functions.invoke(UPDATE_FUNCTION_NAME, {
214
267
  headers: {
@@ -0,0 +1,46 @@
1
+ import { z } from 'zod';
2
+ import cleanObject from '../_shared/clean_object.js';
3
+ import { supabase_base_url, x_region } from '../_shared/config.js';
4
+ const input_schema = {
5
+ query: z.string().min(1).describe('Queries from user'),
6
+ };
7
+ async function searchLifecycleModels({ query }, bearerKey) {
8
+ const url = `${supabase_base_url}/functions/v1/lifecyclemodel_hybrid_search`;
9
+ try {
10
+ const response = await fetch(url, {
11
+ method: 'POST',
12
+ headers: {
13
+ 'Content-Type': 'application/json',
14
+ Authorization: `Bearer ${bearerKey}`,
15
+ 'x-region': x_region,
16
+ },
17
+ body: JSON.stringify(cleanObject({
18
+ query,
19
+ })),
20
+ });
21
+ if (!response.ok) {
22
+ throw new Error(`HTTP error: ${response.status} ${response.statusText}`);
23
+ }
24
+ const data = await response.json();
25
+ return JSON.stringify(data);
26
+ }
27
+ catch (error) {
28
+ console.error('Error making the request:', error);
29
+ throw error;
30
+ }
31
+ }
32
+ export function regLifecycleModelSearchTool(server, bearerKey) {
33
+ server.tool('Search_life_cycle_models_Tool', 'Search LCA life cycle models data.', input_schema, async ({ query }) => {
34
+ const result = await searchLifecycleModels({
35
+ query,
36
+ }, bearerKey);
37
+ return {
38
+ content: [
39
+ {
40
+ type: 'text',
41
+ text: result,
42
+ },
43
+ ],
44
+ };
45
+ });
46
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tiangong-lca/mcp-server",
3
- "version": "0.0.17",
3
+ "version": "0.0.19",
4
4
  "description": "TianGong LCA MCP Server",
5
5
  "license": "MIT",
6
6
  "author": "Nan LI",
@@ -27,23 +27,23 @@
27
27
  "ncu:update": "npx npm-check-updates -u"
28
28
  },
29
29
  "dependencies": {
30
- "@modelcontextprotocol/sdk": "^1.18.2",
31
- "@supabase/supabase-js": "^2.58.0",
30
+ "@modelcontextprotocol/sdk": "^1.20.0",
31
+ "@supabase/supabase-js": "^2.75.0",
32
+ "@tiangong-lca/tidas-sdk": "^0.1.16",
32
33
  "@types/express": "^5.0.3",
33
- "@upstash/redis": "^1.35.4",
34
- "aws-jwt-verify": "^5.1.0",
34
+ "@upstash/redis": "^1.35.5",
35
+ "aws-jwt-verify": "^5.1.1",
35
36
  "olca-ipc": "^2.2.1",
36
37
  "zod": "^3.25.76"
37
38
  },
38
39
  "devDependencies": {
39
- "@modelcontextprotocol/inspector": "^0.16.8",
40
- "@tiangong-lca/tidas-sdk": "^0.1.16",
40
+ "@modelcontextprotocol/inspector": "0.16.8",
41
41
  "dotenv-cli": "^10.0.0",
42
42
  "npm-check-updates": "^19.0.0",
43
43
  "prettier": "^3.6.2",
44
44
  "prettier-plugin-organize-imports": "^4.3.0",
45
45
  "shx": "^0.4.0",
46
46
  "tsx": "^4.20.6",
47
- "typescript": "^5.9.2"
47
+ "typescript": "^5.9.3"
48
48
  }
49
49
  }