@centrali-io/centrali-mcp 3.1.4 → 3.1.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.
@@ -11,6 +11,28 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.registerRecordTools = registerRecordTools;
13
13
  const zod_1 = require("zod");
14
+ function formatError(error, context) {
15
+ var _a, _b;
16
+ if (error && typeof error === 'object') {
17
+ const e = error;
18
+ if ('message' in e) {
19
+ let msg = `Error ${context}`;
20
+ if ('code' in e || 'status' in e) {
21
+ msg += `: [${(_b = (_a = e.code) !== null && _a !== void 0 ? _a : e.status) !== null && _b !== void 0 ? _b : 'ERROR'}] ${e.message}`;
22
+ }
23
+ else {
24
+ msg += `: ${e.message}`;
25
+ }
26
+ if (Array.isArray(e.fieldErrors) && e.fieldErrors.length > 0) {
27
+ msg += '\nField errors:\n' + e.fieldErrors
28
+ .map(f => ` ${f.field}: ${f.message}`)
29
+ .join('\n');
30
+ }
31
+ return msg;
32
+ }
33
+ }
34
+ return `Error ${context}: ${error instanceof Error ? error.message : String(error)}`;
35
+ }
14
36
  function registerRecordTools(server, sdk) {
15
37
  server.tool("query_records", "Query records from a structure with optional filters, sorting, and pagination. Filters use 'data.' prefix for custom fields and bracket notation for operators (e.g., 'data.status': 'active', 'data.price[lte]': 100).", {
16
38
  recordSlug: zod_1.z
@@ -53,7 +75,7 @@ function registerRecordTools(server, sdk) {
53
75
  content: [
54
76
  {
55
77
  type: "text",
56
- text: `Error querying records from '${recordSlug}': ${error.message}`,
78
+ text: formatError(error, `querying records from '${recordSlug}'`),
57
79
  },
58
80
  ],
59
81
  isError: true,
@@ -82,7 +104,7 @@ function registerRecordTools(server, sdk) {
82
104
  content: [
83
105
  {
84
106
  type: "text",
85
- text: `Error getting record '${id}' from '${recordSlug}': ${error.message}`,
107
+ text: formatError(error, `getting record '${id}' from '${recordSlug}'`),
86
108
  },
87
109
  ],
88
110
  isError: true,
@@ -110,7 +132,7 @@ function registerRecordTools(server, sdk) {
110
132
  content: [
111
133
  {
112
134
  type: "text",
113
- text: `Error creating record in '${recordSlug}': ${error.message}`,
135
+ text: formatError(error, `creating record in '${recordSlug}'`),
114
136
  },
115
137
  ],
116
138
  isError: true,
@@ -137,7 +159,7 @@ function registerRecordTools(server, sdk) {
137
159
  content: [
138
160
  {
139
161
  type: "text",
140
- text: `Error updating record '${id}' in '${recordSlug}': ${error.message}`,
162
+ text: formatError(error, `updating record '${id}' in '${recordSlug}'`),
141
163
  },
142
164
  ],
143
165
  isError: true,
@@ -170,9 +192,78 @@ function registerRecordTools(server, sdk) {
170
192
  content: [
171
193
  {
172
194
  type: "text",
173
- text: `Error deleting record '${id}' from '${recordSlug}': ${error.message}`,
195
+ text: formatError(error, `deleting record '${id}' from '${recordSlug}'`),
196
+ },
197
+ ],
198
+ isError: true,
199
+ };
200
+ }
201
+ }));
202
+ server.tool("upsert_record", "Create or update a record atomically. Matches on the provided fields to find an existing record — updates it if found, creates it if not. Returns the record and whether it was 'created' or 'updated'.", {
203
+ recordSlug: zod_1.z.string().describe("The structure's record slug"),
204
+ match: zod_1.z
205
+ .record(zod_1.z.string(), zod_1.z.any())
206
+ .describe("Fields to match on when looking for an existing record (e.g. { sku: 'WIDGET-001' })"),
207
+ data: zod_1.z
208
+ .record(zod_1.z.string(), zod_1.z.any())
209
+ .describe("Full record data to create or update with"),
210
+ }, (_a) => __awaiter(this, [_a], void 0, function* ({ recordSlug, match, data }) {
211
+ try {
212
+ const result = yield sdk.upsertRecord(recordSlug, { match, data });
213
+ return {
214
+ content: [
215
+ {
216
+ type: "text",
217
+ text: JSON.stringify({ operation: result.operation, record: result.data }, null, 2),
174
218
  },
175
219
  ],
220
+ };
221
+ }
222
+ catch (error) {
223
+ return {
224
+ content: [
225
+ { type: "text", text: formatError(error, `upserting record in '${recordSlug}'`) },
226
+ ],
227
+ isError: true,
228
+ };
229
+ }
230
+ }));
231
+ server.tool("get_records_by_ids", "Fetch multiple records by their IDs in a single request. Returns an array of records.", {
232
+ recordSlug: zod_1.z.string().describe("The structure's record slug"),
233
+ ids: zod_1.z.array(zod_1.z.string()).describe("Array of record IDs (UUIDs) to fetch"),
234
+ }, (_a) => __awaiter(this, [_a], void 0, function* ({ recordSlug, ids }) {
235
+ try {
236
+ const result = yield sdk.getRecordsByIds(recordSlug, ids);
237
+ return {
238
+ content: [{ type: "text", text: JSON.stringify(result.data, null, 2) }],
239
+ };
240
+ }
241
+ catch (error) {
242
+ return {
243
+ content: [
244
+ { type: "text", text: formatError(error, `fetching records by IDs from '${recordSlug}'`) },
245
+ ],
246
+ isError: true,
247
+ };
248
+ }
249
+ }));
250
+ server.tool("restore_record", "Restore a soft-deleted record by ID. Only works on records deleted without hard=true.", {
251
+ recordSlug: zod_1.z.string().describe("The structure's record slug"),
252
+ id: zod_1.z.string().describe("The record ID (UUID) to restore"),
253
+ }, (_a) => __awaiter(this, [_a], void 0, function* ({ recordSlug, id }) {
254
+ try {
255
+ yield sdk.restoreRecord(recordSlug, id);
256
+ return {
257
+ content: [
258
+ { type: "text", text: `Record '${id}' restored in '${recordSlug}'.` },
259
+ ],
260
+ };
261
+ }
262
+ catch (error) {
263
+ return {
264
+ content: [
265
+ { type: "text", text: formatError(error, `restoring record '${id}' in '${recordSlug}'`) },
266
+ ],
176
267
  isError: true,
177
268
  };
178
269
  }
@@ -11,6 +11,28 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.registerSearchTools = registerSearchTools;
13
13
  const zod_1 = require("zod");
14
+ function formatError(error, context) {
15
+ var _a, _b;
16
+ if (error && typeof error === 'object') {
17
+ const e = error;
18
+ if ('message' in e) {
19
+ let msg = `Error ${context}`;
20
+ if ('code' in e || 'status' in e) {
21
+ msg += `: [${(_b = (_a = e.code) !== null && _a !== void 0 ? _a : e.status) !== null && _b !== void 0 ? _b : 'ERROR'}] ${e.message}`;
22
+ }
23
+ else {
24
+ msg += `: ${e.message}`;
25
+ }
26
+ if (Array.isArray(e.fieldErrors) && e.fieldErrors.length > 0) {
27
+ msg += '\nField errors:\n' + e.fieldErrors
28
+ .map(f => ` ${f.field}: ${f.message}`)
29
+ .join('\n');
30
+ }
31
+ return msg;
32
+ }
33
+ }
34
+ return `Error ${context}: ${error instanceof Error ? error.message : String(error)}`;
35
+ }
14
36
  function registerSearchTools(server, sdk) {
15
37
  server.tool("search_records", "Full-text search across records in the workspace. Powered by Meilisearch. Optionally filter by structure(s) and limit results.", {
16
38
  query: zod_1.z.string().describe("The search query string"),
@@ -41,7 +63,7 @@ function registerSearchTools(server, sdk) {
41
63
  content: [
42
64
  {
43
65
  type: "text",
44
- text: `Error searching records: ${error.message}`,
66
+ text: formatError(error, "searching records"),
45
67
  },
46
68
  ],
47
69
  isError: true,
@@ -11,6 +11,28 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.registerSmartQueryTools = registerSmartQueryTools;
13
13
  const zod_1 = require("zod");
14
+ function formatError(error, context) {
15
+ var _a, _b;
16
+ if (error && typeof error === 'object') {
17
+ const e = error;
18
+ if ('message' in e) {
19
+ let msg = `Error ${context}`;
20
+ if ('code' in e || 'status' in e) {
21
+ msg += `: [${(_b = (_a = e.code) !== null && _a !== void 0 ? _a : e.status) !== null && _b !== void 0 ? _b : 'ERROR'}] ${e.message}`;
22
+ }
23
+ else {
24
+ msg += `: ${e.message}`;
25
+ }
26
+ if (Array.isArray(e.fieldErrors) && e.fieldErrors.length > 0) {
27
+ msg += '\nField errors:\n' + e.fieldErrors
28
+ .map(f => ` ${f.field}: ${f.message}`)
29
+ .join('\n');
30
+ }
31
+ return msg;
32
+ }
33
+ }
34
+ return `Error ${context}: ${error instanceof Error ? error.message : String(error)}`;
35
+ }
14
36
  function registerSmartQueryTools(server, sdk) {
15
37
  server.tool("list_smart_queries", "List smart queries. Smart queries are reusable, parameterized queries defined in the Centrali console. Optionally filter by structure slug.", {
16
38
  recordSlug: zod_1.z
@@ -33,7 +55,7 @@ function registerSmartQueryTools(server, sdk) {
33
55
  content: [
34
56
  {
35
57
  type: "text",
36
- text: `Error listing smart queries: ${error.message}`,
58
+ text: formatError(error, "listing smart queries"),
37
59
  },
38
60
  ],
39
61
  isError: true,
@@ -64,7 +86,7 @@ function registerSmartQueryTools(server, sdk) {
64
86
  content: [
65
87
  {
66
88
  type: "text",
67
- text: `Error executing smart query '${queryId}': ${error.message}`,
89
+ text: formatError(error, `executing smart query '${queryId}'`),
68
90
  },
69
91
  ],
70
92
  isError: true,
@@ -11,6 +11,28 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.registerStructureTools = registerStructureTools;
13
13
  const zod_1 = require("zod");
14
+ function formatError(error, context) {
15
+ var _a, _b;
16
+ if (error && typeof error === 'object') {
17
+ const e = error;
18
+ if ('message' in e) {
19
+ let msg = `Error ${context}`;
20
+ if ('code' in e || 'status' in e) {
21
+ msg += `: [${(_b = (_a = e.code) !== null && _a !== void 0 ? _a : e.status) !== null && _b !== void 0 ? _b : 'ERROR'}] ${e.message}`;
22
+ }
23
+ else {
24
+ msg += `: ${e.message}`;
25
+ }
26
+ if (Array.isArray(e.fieldErrors) && e.fieldErrors.length > 0) {
27
+ msg += '\nField errors:\n' + e.fieldErrors
28
+ .map(f => ` ${f.field}: ${f.message}`)
29
+ .join('\n');
30
+ }
31
+ return msg;
32
+ }
33
+ }
34
+ return `Error ${context}: ${error instanceof Error ? error.message : String(error)}`;
35
+ }
14
36
  function registerStructureTools(server, sdk) {
15
37
  server.tool("list_structures", "List all data structures (schemas) in the Centrali workspace. Returns name, slug, description, and property definitions for each structure.", {
16
38
  page: zod_1.z.number().optional().describe("Page number (1-indexed)"),
@@ -29,7 +51,7 @@ function registerStructureTools(server, sdk) {
29
51
  content: [
30
52
  {
31
53
  type: "text",
32
- text: `Error listing structures: ${error.message}`,
54
+ text: formatError(error, "listing structures"),
33
55
  },
34
56
  ],
35
57
  isError: true,
@@ -54,7 +76,7 @@ function registerStructureTools(server, sdk) {
54
76
  content: [
55
77
  {
56
78
  type: "text",
57
- text: `Error getting structure '${recordSlug}': ${error.message}`,
79
+ text: formatError(error, `getting structure '${recordSlug}'`),
58
80
  },
59
81
  ],
60
82
  isError: true,
@@ -0,0 +1,3 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { CentraliSDK } from "@centrali-io/centrali-sdk";
3
+ export declare function registerValidationTools(server: McpServer, sdk: CentraliSDK): void;
@@ -0,0 +1,173 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.registerValidationTools = registerValidationTools;
13
+ const zod_1 = require("zod");
14
+ function formatError(error, context) {
15
+ var _a, _b;
16
+ if (error && typeof error === "object") {
17
+ const e = error;
18
+ if ("message" in e) {
19
+ let msg = `Error ${context}`;
20
+ if ("code" in e || "status" in e) {
21
+ msg += `: [${(_b = (_a = e.code) !== null && _a !== void 0 ? _a : e.status) !== null && _b !== void 0 ? _b : "ERROR"}] ${e.message}`;
22
+ }
23
+ else {
24
+ msg += `: ${e.message}`;
25
+ }
26
+ if (Array.isArray(e.fieldErrors) && e.fieldErrors.length > 0) {
27
+ msg +=
28
+ "\nField errors:\n" +
29
+ e.fieldErrors
30
+ .map((f) => ` ${f.field}: ${f.message}`)
31
+ .join("\n");
32
+ }
33
+ return msg;
34
+ }
35
+ }
36
+ return `Error ${context}: ${error instanceof Error ? error.message : String(error)}`;
37
+ }
38
+ function registerValidationTools(server, sdk) {
39
+ server.tool("trigger_validation_scan", "Trigger an AI-powered data quality scan on a structure. Detects typos, format inconsistencies, duplicates, and other data issues. Returns a batchId — use get_validation_summary or list_validation_suggestions to see results after the scan completes.", {
40
+ structureSlug: zod_1.z.string().describe("The structure's record slug to scan"),
41
+ validationTypes: zod_1.z
42
+ .array(zod_1.z.enum(["typo", "format", "duplicate", "semantic", "type"]))
43
+ .optional()
44
+ .describe("Specific validation types to run. If omitted, all types are run."),
45
+ }, (_a) => __awaiter(this, [_a], void 0, function* ({ structureSlug, validationTypes }) {
46
+ try {
47
+ const options = validationTypes ? { validationTypes } : undefined;
48
+ const result = yield sdk.validation.triggerScan(structureSlug, options);
49
+ return {
50
+ content: [{ type: "text", text: JSON.stringify(result.data, null, 2) }],
51
+ };
52
+ }
53
+ catch (error) {
54
+ return {
55
+ content: [
56
+ {
57
+ type: "text",
58
+ text: formatError(error, `triggering validation scan for '${structureSlug}'`),
59
+ },
60
+ ],
61
+ isError: true,
62
+ };
63
+ }
64
+ }));
65
+ server.tool("list_validation_suggestions", "List data quality suggestions generated by validation scans. Each suggestion identifies an issue in a record and proposes a fix.", {
66
+ structureSlug: zod_1.z
67
+ .string()
68
+ .optional()
69
+ .describe("Filter suggestions to a specific structure"),
70
+ status: zod_1.z
71
+ .enum(["pending", "accepted", "rejected", "auto-applied"])
72
+ .optional()
73
+ .describe("Filter by suggestion status (default: all)"),
74
+ issueType: zod_1.z
75
+ .enum(["typo", "format", "duplicate", "semantic", "type"])
76
+ .optional()
77
+ .describe("Filter by issue type"),
78
+ minConfidence: zod_1.z
79
+ .number()
80
+ .optional()
81
+ .describe("Minimum confidence score (0-1). Use 0.9 for high-confidence suggestions only."),
82
+ }, (_a) => __awaiter(this, [_a], void 0, function* ({ structureSlug, status, issueType, minConfidence }) {
83
+ try {
84
+ const options = {};
85
+ if (structureSlug)
86
+ options.structureSlug = structureSlug;
87
+ if (status)
88
+ options.status = status;
89
+ if (issueType)
90
+ options.issueType = issueType;
91
+ if (minConfidence !== undefined)
92
+ options.minConfidence = minConfidence;
93
+ const result = yield sdk.validation.listSuggestions(Object.keys(options).length > 0 ? options : undefined);
94
+ return {
95
+ content: [{ type: "text", text: JSON.stringify(result.data, null, 2) }],
96
+ };
97
+ }
98
+ catch (error) {
99
+ return {
100
+ content: [
101
+ {
102
+ type: "text",
103
+ text: formatError(error, "listing validation suggestions"),
104
+ },
105
+ ],
106
+ isError: true,
107
+ };
108
+ }
109
+ }));
110
+ server.tool("get_validation_summary", "Get a summary of data quality across the workspace — counts of pending, accepted, and rejected suggestions. Optionally filter by structure.", {
111
+ structureSlug: zod_1.z
112
+ .string()
113
+ .optional()
114
+ .describe("Filter summary to a specific structure. If omitted, returns workspace-wide summary."),
115
+ }, (_a) => __awaiter(this, [_a], void 0, function* ({ structureSlug }) {
116
+ try {
117
+ const result = yield sdk.validation.getSummary(structureSlug);
118
+ return {
119
+ content: [{ type: "text", text: JSON.stringify(result.data, null, 2) }],
120
+ };
121
+ }
122
+ catch (error) {
123
+ return {
124
+ content: [
125
+ { type: "text", text: formatError(error, "getting validation summary") },
126
+ ],
127
+ isError: true,
128
+ };
129
+ }
130
+ }));
131
+ server.tool("accept_validation_suggestion", "Accept a data quality suggestion and apply the fix to the record. The suggested correction is written to the record automatically.", {
132
+ suggestionId: zod_1.z.string().describe("The suggestion ID (UUID) to accept"),
133
+ }, (_a) => __awaiter(this, [_a], void 0, function* ({ suggestionId }) {
134
+ try {
135
+ const result = yield sdk.validation.accept(suggestionId);
136
+ return {
137
+ content: [{ type: "text", text: JSON.stringify(result.data, null, 2) }],
138
+ };
139
+ }
140
+ catch (error) {
141
+ return {
142
+ content: [
143
+ {
144
+ type: "text",
145
+ text: formatError(error, `accepting suggestion '${suggestionId}'`),
146
+ },
147
+ ],
148
+ isError: true,
149
+ };
150
+ }
151
+ }));
152
+ server.tool("reject_validation_suggestion", "Reject a data quality suggestion, marking it as incorrect or not applicable. The record is left unchanged.", {
153
+ suggestionId: zod_1.z.string().describe("The suggestion ID (UUID) to reject"),
154
+ }, (_a) => __awaiter(this, [_a], void 0, function* ({ suggestionId }) {
155
+ try {
156
+ const result = yield sdk.validation.reject(suggestionId);
157
+ return {
158
+ content: [{ type: "text", text: JSON.stringify(result.data, null, 2) }],
159
+ };
160
+ }
161
+ catch (error) {
162
+ return {
163
+ content: [
164
+ {
165
+ type: "text",
166
+ text: formatError(error, `rejecting suggestion '${suggestionId}'`),
167
+ },
168
+ ],
169
+ isError: true,
170
+ };
171
+ }
172
+ }));
173
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@centrali-io/centrali-mcp",
3
- "version": "3.1.4",
3
+ "version": "3.1.5",
4
4
  "description": "Centrali MCP Server - AI assistant integration for Centrali workspaces",
5
5
  "main": "dist/index.js",
6
6
  "type": "commonjs",
@@ -25,7 +25,7 @@
25
25
  "author": "Blueinit",
26
26
  "license": "ISC",
27
27
  "dependencies": {
28
- "@centrali-io/centrali-sdk": "^3.1.0",
28
+ "@centrali-io/centrali-sdk": "^3.1.4",
29
29
  "@modelcontextprotocol/sdk": "^1.12.1"
30
30
  },
31
31
  "devDependencies": {
package/src/index.ts CHANGED
@@ -8,6 +8,9 @@ import { registerRecordTools } from "./tools/records.js";
8
8
  import { registerSearchTools } from "./tools/search.js";
9
9
  import { registerComputeTools } from "./tools/compute.js";
10
10
  import { registerSmartQueryTools } from "./tools/smart-queries.js";
11
+ import { registerOrchestrationTools } from "./tools/orchestrations.js";
12
+ import { registerInsightTools } from "./tools/insights.js";
13
+ import { registerValidationTools } from "./tools/validation.js";
11
14
  import { registerStructureResources } from "./resources/structures.js";
12
15
 
13
16
  function getRequiredEnv(name: string): string {
@@ -43,6 +46,9 @@ async function main() {
43
46
  registerSearchTools(server, sdk);
44
47
  registerComputeTools(server, sdk);
45
48
  registerSmartQueryTools(server, sdk);
49
+ registerOrchestrationTools(server, sdk);
50
+ registerInsightTools(server, sdk);
51
+ registerValidationTools(server, sdk);
46
52
 
47
53
  // Register resources
48
54
  registerStructureResources(server, sdk);
@@ -1,6 +1,27 @@
1
1
  import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
2
2
  import { CentraliSDK } from "@centrali-io/centrali-sdk";
3
3
 
4
+ function formatError(error: unknown, context: string): string {
5
+ if (error && typeof error === 'object') {
6
+ const e = error as Record<string, any>;
7
+ if ('message' in e) {
8
+ let msg = `Error ${context}`;
9
+ if ('code' in e || 'status' in e) {
10
+ msg += `: [${e.code ?? e.status ?? 'ERROR'}] ${e.message}`;
11
+ } else {
12
+ msg += `: ${e.message}`;
13
+ }
14
+ if (Array.isArray(e.fieldErrors) && e.fieldErrors.length > 0) {
15
+ msg += '\nField errors:\n' + (e.fieldErrors as Array<{field: string; message: string}>)
16
+ .map(f => ` ${f.field}: ${f.message}`)
17
+ .join('\n');
18
+ }
19
+ return msg;
20
+ }
21
+ }
22
+ return `Error ${context}: ${error instanceof Error ? error.message : String(error)}`;
23
+ }
24
+
4
25
  export function registerStructureResources(
5
26
  server: McpServer,
6
27
  sdk: CentraliSDK
@@ -15,23 +36,27 @@ export function registerStructureResources(
15
36
  mimeType: "application/json",
16
37
  },
17
38
  async (uri) => {
18
- const result = await sdk.structures.list({ limit: 100 });
19
- const summary = (result.data || []).map((s) => ({
20
- name: s.name,
21
- recordSlug: s.recordSlug,
22
- description: s.description || "",
23
- propertyCount: s.properties?.length || 0,
24
- status: s.status,
25
- }));
26
- return {
27
- contents: [
28
- {
29
- uri: uri.href,
30
- mimeType: "application/json",
31
- text: JSON.stringify(summary, null, 2),
32
- },
33
- ],
34
- };
39
+ try {
40
+ const result = await sdk.structures.list({ limit: 100 });
41
+ const summary = (result.data || []).map((s) => ({
42
+ name: s.name,
43
+ recordSlug: s.recordSlug,
44
+ description: s.description || "",
45
+ propertyCount: s.properties?.length || 0,
46
+ status: s.status,
47
+ }));
48
+ return {
49
+ contents: [
50
+ {
51
+ uri: uri.href,
52
+ mimeType: "application/json",
53
+ text: JSON.stringify(summary, null, 2),
54
+ },
55
+ ],
56
+ };
57
+ } catch (error: unknown) {
58
+ throw new Error(formatError(error, "listing structures resource"));
59
+ }
35
60
  }
36
61
  );
37
62
 
@@ -40,15 +65,19 @@ export function registerStructureResources(
40
65
  "structure-schema",
41
66
  new ResourceTemplate("centrali://structures/{slug}", {
42
67
  list: async () => {
43
- const result = await sdk.structures.list({ limit: 100 });
44
- return {
45
- resources: (result.data || []).map((s) => ({
46
- uri: `centrali://structures/${s.recordSlug}`,
47
- name: s.name,
48
- description: s.description || `Schema for ${s.name}`,
49
- mimeType: "application/json",
50
- })),
51
- };
68
+ try {
69
+ const result = await sdk.structures.list({ limit: 100 });
70
+ return {
71
+ resources: (result.data || []).map((s) => ({
72
+ uri: `centrali://structures/${s.recordSlug}`,
73
+ name: s.name,
74
+ description: s.description || `Schema for ${s.name}`,
75
+ mimeType: "application/json",
76
+ })),
77
+ };
78
+ } catch (error: unknown) {
79
+ throw new Error(formatError(error, "listing structure schemas"));
80
+ }
52
81
  },
53
82
  }),
54
83
  {
@@ -56,16 +85,20 @@ export function registerStructureResources(
56
85
  mimeType: "application/json",
57
86
  },
58
87
  async (uri, { slug }) => {
59
- const result = await sdk.structures.getBySlug(slug as string);
60
- return {
61
- contents: [
62
- {
63
- uri: uri.href,
64
- mimeType: "application/json",
65
- text: JSON.stringify(result.data, null, 2),
66
- },
67
- ],
68
- };
88
+ try {
89
+ const result = await sdk.structures.getBySlug(slug as string);
90
+ return {
91
+ contents: [
92
+ {
93
+ uri: uri.href,
94
+ mimeType: "application/json",
95
+ text: JSON.stringify(result.data, null, 2),
96
+ },
97
+ ],
98
+ };
99
+ } catch (error: unknown) {
100
+ throw new Error(formatError(error, `getting structure schema for '${slug}'`));
101
+ }
69
102
  }
70
103
  );
71
104
  }