@tiangong-lca/mcp-server 0.0.27 → 0.0.28

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,11 +1,11 @@
1
1
  import { createClient, FunctionRegion } from '@supabase/supabase-js';
2
- import { createContact, createFlow, createLifeCycleModel, createProcess, createSource, } from '@tiangong-lca/tidas-sdk/core';
3
2
  import { z } from 'zod';
4
3
  import { supabase_base_url, supabase_publishable_key } from '../_shared/config.js';
5
4
  import { resolveSupabaseAccessToken } from '../_shared/supabase_session.js';
6
5
  const allowedTables = ['contacts', 'flows', 'lifecyclemodels', 'processes', 'sources'];
7
6
  const tableSchema = z.enum(allowedTables);
8
7
  const UPDATE_FUNCTION_NAME = 'update_data';
8
+ const MAX_VALIDATION_ERROR_LENGTH = 4_000;
9
9
  const tablePrimaryKey = {
10
10
  contacts: 'id',
11
11
  flows: 'id',
@@ -16,21 +16,13 @@ const tablePrimaryKey = {
16
16
  function getPrimaryKeyColumn(table) {
17
17
  return tablePrimaryKey[table] ?? 'id';
18
18
  }
19
- const jsonValueSchema = z.lazy(() => z.union([
20
- z.string(),
21
- z.number(),
22
- z.boolean(),
23
- z.null(),
24
- z.array(jsonValueSchema),
25
- z.record(jsonValueSchema),
26
- ]));
27
19
  const filterValueSchema = z.union([
28
20
  z.string(),
29
21
  z.number(),
30
22
  z.boolean(),
31
23
  z.null(),
32
24
  ]);
33
- const filtersSchema = z.record(filterValueSchema);
25
+ const filtersSchema = z.record(z.string(), filterValueSchema);
34
26
  const toolParamsSchema = {
35
27
  operation: z
36
28
  .enum(['select', 'insert', 'update', 'delete'])
@@ -55,7 +47,8 @@ const toolParamsSchema = {
55
47
  filters: filtersSchema
56
48
  .optional()
57
49
  .describe('Optional equality filters as JSON object, e.g. { "name": "Example" }. Only used for select operations. Leave empty for insert/update/delete operations.'),
58
- jsonOrdered: jsonValueSchema
50
+ jsonOrdered: z
51
+ .unknown()
59
52
  .optional()
60
53
  .describe('JSON value persisted into json_ordered (required for insert/update; omit for select/delete).'),
61
54
  };
@@ -123,6 +116,36 @@ const refinedInputSchema = z
123
116
  break;
124
117
  }
125
118
  });
119
+ let tidasValidationFactoryMapPromise;
120
+ function summarizeError(error) {
121
+ if (error instanceof Error) {
122
+ return error.message;
123
+ }
124
+ try {
125
+ const serialized = JSON.stringify(error);
126
+ if (!serialized) {
127
+ return String(error);
128
+ }
129
+ return serialized.length > MAX_VALIDATION_ERROR_LENGTH
130
+ ? `${serialized.slice(0, MAX_VALIDATION_ERROR_LENGTH)}...`
131
+ : serialized;
132
+ }
133
+ catch {
134
+ return String(error);
135
+ }
136
+ }
137
+ async function getTidasValidationFactoryMap() {
138
+ if (!tidasValidationFactoryMapPromise) {
139
+ tidasValidationFactoryMapPromise = import('@tiangong-lca/tidas-sdk/core').then((module) => ({
140
+ contacts: module.createContact,
141
+ flows: module.createFlow,
142
+ lifecyclemodels: module.createLifeCycleModel,
143
+ processes: module.createProcess,
144
+ sources: module.createSource,
145
+ }));
146
+ }
147
+ return tidasValidationFactoryMapPromise;
148
+ }
126
149
  function requireAccessToken(accessToken) {
127
150
  if (!accessToken) {
128
151
  throw new Error('An authenticated Supabase session is required for update operations. Provide a valid access token.');
@@ -135,44 +158,13 @@ function ensureRows(rows, errorMessage) {
135
158
  }
136
159
  return rows;
137
160
  }
138
- function validateJsonOrdered(table, jsonOrdered) {
161
+ async function validateJsonOrdered(table, jsonOrdered) {
139
162
  try {
140
- let validationResult;
141
- switch (table) {
142
- case 'contacts': {
143
- const contact = createContact(jsonOrdered, { mode: 'strict' });
144
- validationResult = contact.validate();
145
- break;
146
- }
147
- case 'flows': {
148
- const flow = createFlow(jsonOrdered, { mode: 'strict' });
149
- validationResult = flow.validate();
150
- break;
151
- }
152
- case 'lifecyclemodels': {
153
- const lifecycleModel = createLifeCycleModel(jsonOrdered, { mode: 'strict' });
154
- validationResult = lifecycleModel.validate();
155
- break;
156
- }
157
- case 'processes': {
158
- const process = createProcess(jsonOrdered, { mode: 'strict' });
159
- validationResult = process.validate();
160
- break;
161
- }
162
- case 'sources': {
163
- const source = createSource(jsonOrdered, { mode: 'strict' });
164
- validationResult = source.validate();
165
- break;
166
- }
167
- default: {
168
- const exhaustiveCheck = table;
169
- throw new Error(`Unsupported table type: ${table}`);
170
- }
171
- }
163
+ const validationFactoryMap = await getTidasValidationFactoryMap();
164
+ const createValidator = validationFactoryMap[table];
165
+ const validationResult = createValidator(jsonOrdered, { mode: 'strict' }).validate();
172
166
  if (!validationResult.success) {
173
- const errorDetails = validationResult.error?.issues
174
- ? JSON.stringify(validationResult.error.issues, null, 2)
175
- : JSON.stringify(validationResult.error);
167
+ const errorDetails = summarizeError(validationResult.error);
176
168
  throw new Error(`Validation failed for table "${table}". Errors: ${errorDetails}`);
177
169
  }
178
170
  }
@@ -246,11 +238,12 @@ async function handleInsert(supabase, input) {
246
238
  if (id === undefined) {
247
239
  throw new Error('id is required for insert operations.');
248
240
  }
249
- validateJsonOrdered(table, jsonOrdered);
241
+ const jsonOrderedValue = jsonOrdered;
242
+ await validateJsonOrdered(table, jsonOrderedValue);
250
243
  const keyColumn = getPrimaryKeyColumn(table);
251
244
  const { data, error } = await supabase
252
245
  .from(table)
253
- .insert([{ [keyColumn]: id, json_ordered: jsonOrdered }])
246
+ .insert([{ [keyColumn]: id, json_ordered: jsonOrderedValue }])
254
247
  .select();
255
248
  if (error) {
256
249
  console.error('Error inserting into the database:', error);
@@ -269,13 +262,14 @@ async function handleUpdate(supabase, accessToken, input) {
269
262
  if (jsonOrdered === undefined) {
270
263
  throw new Error('jsonOrdered is required for update operations.');
271
264
  }
272
- validateJsonOrdered(table, jsonOrdered);
265
+ const jsonOrderedValue = jsonOrdered;
266
+ await validateJsonOrdered(table, jsonOrderedValue);
273
267
  const token = requireAccessToken(accessToken);
274
268
  const { data: functionPayload, error } = await supabase.functions.invoke(UPDATE_FUNCTION_NAME, {
275
269
  headers: {
276
270
  Authorization: `Bearer ${token}`,
277
271
  },
278
- body: { id, version, table, data: { json_ordered: jsonOrdered } },
272
+ body: { id, version, table, data: { json_ordered: jsonOrderedValue } },
279
273
  region: FunctionRegion.UsEast1,
280
274
  });
281
275
  if (error) {
@@ -50,7 +50,7 @@ const jsonValueSchema = z.lazy(() => z.union([
50
50
  z.boolean(),
51
51
  z.null(),
52
52
  z.array(jsonValueSchema),
53
- z.record(jsonValueSchema),
53
+ z.record(z.string(), jsonValueSchema),
54
54
  ]));
55
55
  function validateTidasData(entityType, data) {
56
56
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tiangong-lca/mcp-server",
3
- "version": "0.0.27",
3
+ "version": "0.0.28",
4
4
  "description": "TianGong LCA MCP Server",
5
5
  "license": "MIT",
6
6
  "author": "Nan LI",
@@ -28,19 +28,19 @@
28
28
  "ncu:update": "npx npm-check-updates -u"
29
29
  },
30
30
  "dependencies": {
31
- "@modelcontextprotocol/sdk": "^1.25.3",
32
- "@supabase/supabase-js": "^2.91.1",
33
- "@tiangong-lca/tidas-sdk": "^0.1.29",
31
+ "@modelcontextprotocol/sdk": "^1.26.0",
32
+ "@supabase/supabase-js": "^2.95.3",
33
+ "@tiangong-lca/tidas-sdk": "^0.1.30",
34
34
  "@types/express": "^5.0.6",
35
- "@upstash/redis": "^1.36.1",
35
+ "@upstash/redis": "^1.36.2",
36
36
  "aws-jwt-verify": "^5.1.1",
37
37
  "olca-ipc": "^2.2.1",
38
- "zod": "^3.25.76"
38
+ "zod": "^4.3.6"
39
39
  },
40
40
  "devDependencies": {
41
41
  "@modelcontextprotocol/inspector": "^0.19.0",
42
42
  "dotenv-cli": "^11.0.0",
43
- "npm-check-updates": "^19.3.1",
43
+ "npm-check-updates": "^19.3.2",
44
44
  "prettier": "^3.8.1",
45
45
  "prettier-plugin-organize-imports": "^4.3.0",
46
46
  "shx": "^0.4.0",