@enfyra/mcp-server 0.0.20 → 0.0.21
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
|
@@ -65,6 +65,8 @@ export function buildMcpServerInstructions(apiBaseUrl) {
|
|
|
65
65
|
'### After a new table is created',
|
|
66
66
|
'- MCP **`create_table` supports creating columns and relations in the same call**: pass `columns` and `relations` as JSON arrays. Use `create_relation` only when adding a relation to an existing table later.',
|
|
67
67
|
'- In `create_table.relations`, each relation uses `targetTable` (table id or `{id}`), `type`, `propertyName`, optional `inversePropertyName` or `mappedBy`, `isNullable`, `onDelete`, and `description`. The target table must already exist.',
|
|
68
|
+
'- **Never ask for or provide physical FK column names** when creating/updating relations. Do not include `fkCol`, `fkColumn`, `foreignKeyColumn`, `sourceColumn`, `targetColumn`, `junctionSourceColumn`, or `junctionTargetColumn` in create/update payloads unless you are only displaying existing metadata. Enfyra relation cascade derives physical FK/junction names from `propertyName` and table metadata, then hides FK columns from app form/schema definition.',
|
|
69
|
+
'- For relation CRUD payloads, the public interface is the relation `propertyName`: example create body uses `"author": {"id": 1}`, not `"authorId"` or a physical FK column. Query/deep/filter keys also use relation `propertyName`.',
|
|
68
70
|
'- Enfyra creates a **default** route at `/{table_name}` using the table **name** from `create_table` (not the alias). Prefer **`create_route`** for additional or custom paths instead of new tables.',
|
|
69
71
|
'- **Four REST HTTP operations** on that resource:',
|
|
70
72
|
` - **GET** \`${getList}\` — list / filter (query: filter, sort, page, limit, fields, meta).`,
|
package/src/lib/table-tools.js
CHANGED
|
@@ -43,7 +43,20 @@ function parseJsonArrayParam(name, value) {
|
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
function normalizeRelationForTablePatch(relation) {
|
|
46
|
-
const {
|
|
46
|
+
const {
|
|
47
|
+
sourceTable,
|
|
48
|
+
targetTable,
|
|
49
|
+
targetTableId,
|
|
50
|
+
mappedBy,
|
|
51
|
+
fkCol,
|
|
52
|
+
fkColumn,
|
|
53
|
+
foreignKeyColumn,
|
|
54
|
+
sourceColumn,
|
|
55
|
+
targetColumn,
|
|
56
|
+
junctionSourceColumn,
|
|
57
|
+
junctionTargetColumn,
|
|
58
|
+
...rest
|
|
59
|
+
} = relation;
|
|
47
60
|
const normalized = { ...rest };
|
|
48
61
|
const resolvedTargetTable =
|
|
49
62
|
targetTableId ??
|
|
@@ -90,6 +103,7 @@ export function registerTableTools(server, ENFYRA_API_URL) {
|
|
|
90
103
|
'**Not** for adding a custom API path or handler only — for that use **`create_route`** with an existing `mainTableId`. Use **`create_table`** when the user needs new stored data (new entity).',
|
|
91
104
|
'PREFERRED: pass `columns` and `relations` params as JSON arrays to create a table WITH columns and relations in one call (cascade). Only use create_column/create_relation separately when adding to an existing table later.',
|
|
92
105
|
'Relations are supported in this same create_table call when the target table already exists. Each relation uses { targetTable, type, propertyName, inversePropertyName?, mappedBy?, isNullable?, onDelete? }; targetTable may be a table id or {id}.',
|
|
106
|
+
'Do NOT provide physical FK/junction columns. Never include fkCol, fkColumn, foreignKeyColumn, sourceColumn, targetColumn, junctionSourceColumn, or junctionTargetColumn. Enfyra derives and hides those physical columns from relation propertyName/table metadata.',
|
|
93
107
|
'Schema operations (create/update/delete table, add column) must run one at a time — migration locks DB; parallel calls will fail.',
|
|
94
108
|
'Enfyra auto-creates a default REST route at path `/<table_name>` (same segment as `name`, not alias).',
|
|
95
109
|
'REST surface for that route (matches server route engine): 4 HTTP operations — GET `/<table>` (list/filter), POST `/<table>` (create), PATCH `/<table>/:id` (update), DELETE `/<table>/:id` (delete).',
|
|
@@ -102,7 +116,7 @@ export function registerTableTools(server, ENFYRA_API_URL) {
|
|
|
102
116
|
alias: z.string().optional().describe('Table alias for API. If not provided, the table name will be used.'),
|
|
103
117
|
description: z.string().optional().describe('Description of what this table stores.'),
|
|
104
118
|
columns: z.string().optional().describe('JSON array of column definitions to create with the table (cascade). Each column: { name, type, isNullable?, isUnique?, defaultValue?, description?, options? }. The `id` column is always auto-included. Example: [{"name":"title","type":"varchar"},{"name":"status","type":"enum","options":["draft","published"]}]'),
|
|
105
|
-
relations: z.string().optional().describe('JSON array of relation definitions to create with the table in the same cascade call. Each relation: { targetTable, type, propertyName, inversePropertyName?, mappedBy?, isNullable?, onDelete?, description? }. targetTable can be an id or {"id": <id>}. Example: [{"targetTable":2,"type":"many-to-one","propertyName":"author","inversePropertyName":"posts","isNullable":false,"onDelete":"CASCADE"}]'),
|
|
119
|
+
relations: z.string().optional().describe('JSON array of relation definitions to create with the table in the same cascade call. Each relation: { targetTable, type, propertyName, inversePropertyName?, mappedBy?, isNullable?, onDelete?, description? }. targetTable can be an id or {"id": <id>}. Do not include physical FK/junction columns such as fkCol, foreignKeyColumn, sourceColumn, targetColumn, junctionSourceColumn, or junctionTargetColumn; Enfyra derives them and hides FK columns from app schema. Example: [{"targetTable":2,"type":"many-to-one","propertyName":"author","inversePropertyName":"posts","isNullable":false,"onDelete":"CASCADE"}]'),
|
|
106
120
|
},
|
|
107
121
|
async ({ name, alias, description, columns: columnsJson, relations: relationsJson }) => {
|
|
108
122
|
const idColumn = { name: 'id', type: 'int', isPrimary: true, isGenerated: true, isNullable: false };
|
|
@@ -316,7 +330,8 @@ export function registerTableTools(server, ENFYRA_API_URL) {
|
|
|
316
330
|
'create_relation',
|
|
317
331
|
[
|
|
318
332
|
'Create a relation between two tables (many-to-one, one-to-many, one-to-one, many-to-many).',
|
|
319
|
-
'For many-to-one: a FK column is created on the source table. For one-to-many: the FK is on the target (inverse relation).',
|
|
333
|
+
'For many-to-one: a physical FK column is created on the source table. For one-to-many: the FK is on the target (inverse relation). This physical FK is derived by Enfyra and hidden from app schema/forms.',
|
|
334
|
+
'Never ask the user for physical FK column names and never send fkCol/fkColumn/foreignKeyColumn/sourceColumn/targetColumn/junction*Column. The public API uses relation propertyName only.',
|
|
320
335
|
'Run sequentially — DB migration locks per operation.',
|
|
321
336
|
].join(' '),
|
|
322
337
|
{
|
package/src/mcp-server-entry.mjs
CHANGED
|
@@ -355,6 +355,7 @@ server.tool(
|
|
|
355
355
|
relations: routeTables.has('relation_definition')
|
|
356
356
|
? 'relation_definition has a REST route for reads/metadata, but canonical schema migration is create_relation/delete_relation or table_definition PATCH with the full relations array. Relation onDelete accepts CASCADE, SET NULL, or RESTRICT.'
|
|
357
357
|
: 'Use create_relation/delete_relation or table_definition PATCH with the full relations array. Relation onDelete accepts CASCADE, SET NULL, or RESTRICT.',
|
|
358
|
+
relationCascadeFkContract: 'Do not ask for or send physical FK/junction column names in relation create/update payloads. Enfyra derives fk/junction columns from relation propertyName/table metadata and hides FK columns from app schema/forms. Use targetTable, type, propertyName, inversePropertyName or mappedBy, isNullable, onDelete.',
|
|
358
359
|
tableDefinitionRelations: (tableDefinition?.relations || []).map((rel) => rel.propertyName),
|
|
359
360
|
relationDefinitionRelations: (relationTable?.relations || []).map((rel) => rel.propertyName),
|
|
360
361
|
},
|
|
@@ -511,6 +512,7 @@ server.tool(
|
|
|
511
512
|
backendNotes: {
|
|
512
513
|
primaryKey: 'SQL commonly uses id; Mongo uses _id. Use table metadata primary column when available.',
|
|
513
514
|
relationNames: 'API relation operations use relation propertyName, not physical FK column names.',
|
|
515
|
+
relationCascadeFkContract: 'When creating relations through create_table/create_relation/table_definition PATCH, never provide fkCol/fkColumn/foreignKeyColumn/sourceColumn/targetColumn/junction*Column. These are physical implementation details derived by Enfyra and hidden from app schema/forms.',
|
|
514
516
|
graphql: 'GraphQL query args also accept filter/sort/page/limit, but GraphQL requires Bearer auth and table enablement via gql_definition.',
|
|
515
517
|
},
|
|
516
518
|
table: tableName
|
|
@@ -997,6 +999,7 @@ server.tool(
|
|
|
997
999
|
fields: 'Use column names and relation propertyName values.',
|
|
998
1000
|
filter: 'Use query DSL operators on column names or nested relation propertyName objects.',
|
|
999
1001
|
deep: 'Deep fetch keys are relation propertyName values.',
|
|
1002
|
+
relationMutation: 'For relation schema creation/update use targetTable/type/propertyName/inversePropertyName|mappedBy/isNullable/onDelete only. Do not provide physical FK/junction columns; Enfyra derives and hides them.',
|
|
1000
1003
|
},
|
|
1001
1004
|
};
|
|
1002
1005
|
|