@enfyra/mcp-server 0.0.73 → 0.0.75
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/package.json
CHANGED
|
@@ -135,7 +135,7 @@ export function buildMcpServerInstructions(apiBaseUrl) {
|
|
|
135
135
|
'- Each route has **publishedMethods** (which HTTP verbs are “public”) and **routePermissions** (roles/users for protected access).',
|
|
136
136
|
'- If the **current request method** is listed in **publishedMethods** for that route, the server allows the call **without** a Bearer token (`RoleGuard`).',
|
|
137
137
|
'- Otherwise the client must send an **Authorization** header with **Bearer** JWT from login. Then the user must satisfy **routePermissions** (unless root admin).',
|
|
138
|
-
'- Owner-scoped GET handlers must preserve caller filters and merge the owner scope for normal users, while root admin operational views may bypass
|
|
138
|
+
'- Owner-scoped GET handlers must preserve caller filters and merge the owner scope for normal users, while root admin operational views may bypass only the owner scope with `@USER.isRootAdmin` and must keep caller filters intact. Never replace `@QUERY.filter` with `{}` for root admins; doing so breaks detail reads, pagination, and `debugMode=true` explain checks.',
|
|
139
139
|
'- MCP tools that use `fetchAPI` authenticate with the configured `ENFYRA_API_TOKEN`. Explain to users that **direct HTTP** calls need a Bearer token unless the route/method is published.',
|
|
140
140
|
'',
|
|
141
141
|
'### Post-hooks (REST)',
|
package/src/lib/table-tools.js
CHANGED
|
@@ -16,8 +16,11 @@ const FORBIDDEN_RELATION_KEYS = [
|
|
|
16
16
|
'fkCol',
|
|
17
17
|
'fkColumn',
|
|
18
18
|
'foreignKeyColumn',
|
|
19
|
+
'referencedColumn',
|
|
20
|
+
'constraintName',
|
|
19
21
|
'sourceColumn',
|
|
20
22
|
'targetColumn',
|
|
23
|
+
'junctionTableName',
|
|
21
24
|
'junctionSourceColumn',
|
|
22
25
|
'junctionTargetColumn',
|
|
23
26
|
];
|
|
@@ -144,6 +147,23 @@ export function normalizeRelationForTablePatch(relation) {
|
|
|
144
147
|
return normalized;
|
|
145
148
|
}
|
|
146
149
|
|
|
150
|
+
export function sanitizeExistingRelationForTablePatch(relation) {
|
|
151
|
+
const {
|
|
152
|
+
fkCol,
|
|
153
|
+
fkColumn,
|
|
154
|
+
foreignKeyColumn,
|
|
155
|
+
referencedColumn,
|
|
156
|
+
constraintName,
|
|
157
|
+
sourceColumn,
|
|
158
|
+
targetColumn,
|
|
159
|
+
junctionTableName,
|
|
160
|
+
junctionSourceColumn,
|
|
161
|
+
junctionTargetColumn,
|
|
162
|
+
...rest
|
|
163
|
+
} = relation;
|
|
164
|
+
return normalizeRelationForTablePatch(rest);
|
|
165
|
+
}
|
|
166
|
+
|
|
147
167
|
export function resolveRelationTargetsFromMetadata(metadata, relations) {
|
|
148
168
|
return relations.map((relation) => {
|
|
149
169
|
const targetTable = relation.targetTable;
|
|
@@ -210,7 +230,7 @@ async function verifyRelationCascade(ENFYRA_API_URL, tableId, beforeIds, {
|
|
|
210
230
|
propertyName,
|
|
211
231
|
}) {
|
|
212
232
|
const tableData = await fetchTableWithDetails(ENFYRA_API_URL, tableId);
|
|
213
|
-
const afterRelations = (tableData.relations || []).map(
|
|
233
|
+
const afterRelations = (tableData.relations || []).map(sanitizeExistingRelationForTablePatch);
|
|
214
234
|
const afterIds = afterRelations.map((relation) => String(getId(relation))).filter((id) => id !== 'null');
|
|
215
235
|
const excludedIds = action === 'delete' ? [relationId] : [];
|
|
216
236
|
const missingIds = getMissingIds(beforeIds, afterIds, excludedIds);
|
|
@@ -293,7 +313,7 @@ export function registerTableTools(server, ENFYRA_API_URL) {
|
|
|
293
313
|
if (!tableData) {
|
|
294
314
|
return { content: [{ type: 'text', text: `Error: Table with ID ${sourceTableId} not found.` }] };
|
|
295
315
|
}
|
|
296
|
-
const existingRelations = (tableData.relations || []).map(
|
|
316
|
+
const existingRelations = (tableData.relations || []).map(sanitizeExistingRelationForTablePatch);
|
|
297
317
|
const beforeIds = existingRelations.map((relation) => String(getId(relation))).filter((id) => id !== 'null');
|
|
298
318
|
const newRelation = { targetTable: targetTableId, type, propertyName };
|
|
299
319
|
if (inversePropertyName !== undefined) newRelation.inversePropertyName = inversePropertyName || null;
|
|
@@ -361,7 +381,7 @@ export function registerTableTools(server, ENFYRA_API_URL) {
|
|
|
361
381
|
return { content: [{ type: 'text', text: `Error: Table with ID ${tableId} not found.` }] };
|
|
362
382
|
}
|
|
363
383
|
|
|
364
|
-
const existingRelations = (tableData.relations || []).map(
|
|
384
|
+
const existingRelations = (tableData.relations || []).map(sanitizeExistingRelationForTablePatch);
|
|
365
385
|
const beforeIds = existingRelations.map((relation) => String(getId(relation))).filter((id) => id !== 'null');
|
|
366
386
|
if (!beforeIds.includes(String(relationId))) {
|
|
367
387
|
throw new Error(`Relation ${relationId} was not found on table ${tableId}; refusing schema cascade patch.`);
|