@enfyra/mcp-server 0.0.93 → 0.0.94
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 +1 -1
- package/src/lib/mcp-instructions.js +1 -0
- package/src/mcp-server-entry.mjs +36 -15
package/package.json
CHANGED
|
@@ -24,6 +24,7 @@ export function buildMcpServerInstructions(apiBaseUrl) {
|
|
|
24
24
|
`GraphQL endpoints: \`${graphqlHttpUrl}\` and \`${graphqlSchemaUrl}\`.`,
|
|
25
25
|
'',
|
|
26
26
|
'### Work Flow',
|
|
27
|
+
'- For a quick target/base sanity check, call `get_enfyra_api_context`; do not call broad discovery just to confirm which instance this MCP is connected to.',
|
|
27
28
|
'- Discover before deciding. For architecture/capability questions call `discover_enfyra_system`; for DB/pk/runtime/cache context call `discover_runtime_context`; for filters/deep/sort/relation query shape call `discover_query_capabilities`. Run broad discovery tools sequentially, not in parallel.',
|
|
28
29
|
'- Inspect narrowly. Use `inspect_table`, `inspect_route`, and `inspect_feature` for the table/route/feature being changed instead of loading broad metadata.',
|
|
29
30
|
'- Load examples only when needed. Before generating schemas, app connection code, OAuth, Socket.IO, handlers/hooks, flows, files, guards, permissions, or extensions, call `get_enfyra_examples` with the matching category.',
|
package/src/mcp-server-entry.mjs
CHANGED
|
@@ -391,6 +391,10 @@ function collectPartialErrors(results) {
|
|
|
391
391
|
.map(([name, result]) => ({ name, error: result.error }));
|
|
392
392
|
}
|
|
393
393
|
|
|
394
|
+
function jsonContent(payload, { pretty = false } = {}) {
|
|
395
|
+
return { content: [{ type: 'text', text: JSON.stringify(payload, null, pretty ? 2 : 0) }] };
|
|
396
|
+
}
|
|
397
|
+
|
|
394
398
|
async function getMetadataTables() {
|
|
395
399
|
const metadata = await fetchAPI(ENFYRA_API_URL, '/metadata');
|
|
396
400
|
return {
|
|
@@ -615,7 +619,7 @@ server.tool('get_all_metadata', 'Get concise metadata summary for all tables. Us
|
|
|
615
619
|
...summarizeMetadata(result, { search, limit }),
|
|
616
620
|
detailHint: 'Default response is capped and minimal. Call get_table_metadata({ tableName }) or inspect_table({ tableName }) for columns, relations, and route context.',
|
|
617
621
|
};
|
|
618
|
-
return
|
|
622
|
+
return jsonContent(payload);
|
|
619
623
|
});
|
|
620
624
|
|
|
621
625
|
server.tool('get_table_metadata', 'Get concise metadata for a specific table by name', {
|
|
@@ -632,7 +636,7 @@ server.tool('get_table_metadata', 'Get concise metadata for a specific table by
|
|
|
632
636
|
table: summarizeTable(table),
|
|
633
637
|
queryHint: `Use query_table({ tableName: "${tableName}", fields: [...] }) for records. query_table without fields returns only the primary key.`,
|
|
634
638
|
};
|
|
635
|
-
return
|
|
639
|
+
return jsonContent(payload);
|
|
636
640
|
});
|
|
637
641
|
|
|
638
642
|
server.tool(
|
|
@@ -646,7 +650,7 @@ server.tool(
|
|
|
646
650
|
},
|
|
647
651
|
async ({ category }) => {
|
|
648
652
|
const result = getExamples(category);
|
|
649
|
-
return
|
|
653
|
+
return jsonContent(result);
|
|
650
654
|
},
|
|
651
655
|
);
|
|
652
656
|
|
|
@@ -655,6 +659,7 @@ server.tool(
|
|
|
655
659
|
[
|
|
656
660
|
'Call this first when you need to understand the live Enfyra instance.',
|
|
657
661
|
'Returns a concise capability map from live metadata/routes/method rows, including schema management, REST route behavior, GraphQL enablement, and relation handling.',
|
|
662
|
+
'Do not use this only to confirm the API base; use get_enfyra_api_context for that cheaper target check.',
|
|
658
663
|
'Run broad discovery tools sequentially; do not call multiple broad discovery tools in parallel.',
|
|
659
664
|
].join(' '),
|
|
660
665
|
{},
|
|
@@ -672,6 +677,13 @@ server.tool(
|
|
|
672
677
|
const tableDefinition = tables.find((table) => table?.name === 'enfyra_table');
|
|
673
678
|
const gqlDefinition = tables.find((table) => table?.name === 'enfyra_graphql');
|
|
674
679
|
const routeTableList = [...routeTables].sort();
|
|
680
|
+
const noRouteTableList = noRouteTables.sort();
|
|
681
|
+
const sample = (items, max = 40) => ({
|
|
682
|
+
total: items.length,
|
|
683
|
+
returned: Math.min(items.length, max),
|
|
684
|
+
items: items.slice(0, max),
|
|
685
|
+
truncated: items.length > max,
|
|
686
|
+
});
|
|
675
687
|
|
|
676
688
|
const payload = {
|
|
677
689
|
targetInstance: targetInstance(),
|
|
@@ -692,10 +704,12 @@ server.tool(
|
|
|
692
704
|
rest: {
|
|
693
705
|
routePattern: 'Dynamic REST routes expose GET/POST at /<route-path> and PATCH/DELETE at /<route-path>/:id; there is no GET /<route-path>/:id.',
|
|
694
706
|
publicAccess: 'publicMethods controls anonymous REST access per route/method; otherwise Bearer JWT + routePermissions apply.',
|
|
695
|
-
routeTables: routeTableList,
|
|
696
|
-
noRouteTables,
|
|
707
|
+
routeTables: sample(routeTableList),
|
|
708
|
+
noRouteTables: sample(noRouteTableList),
|
|
697
709
|
canonicalCrudTools: 'query_table/create_record/update_record/delete_record use dynamic REST routes and only work for route-backed tables.',
|
|
698
710
|
customRouteWorkflow: 'For a new endpoint use create_route without mainTableId, then create_handler/create_pre_hook/create_post_hook. Do not create a table just to get a path.',
|
|
711
|
+
routeSamples: sample(routes, 25),
|
|
712
|
+
detailHint: 'Use get_all_routes({ search, limit }) or inspect_route({ path }) for route details. Use inspect_table({ tableName }) for table detail.',
|
|
699
713
|
},
|
|
700
714
|
schemaManagement: {
|
|
701
715
|
createTable: 'POST /enfyra_table supports isSingleRecord at create time and supports columns and relations arrays in the same cascade call. MCP create_table exposes isSingleRecord, columns, and relations directly. It does not accept alias at create time; table name drives the default route/schema behavior.',
|
|
@@ -723,11 +737,10 @@ server.tool(
|
|
|
723
737
|
: 'Use update_table graphqlEnabled, then reload_graphql if needed.',
|
|
724
738
|
gqlDefinitionColumns: (gqlDefinition?.columns || []).map((column) => column.name),
|
|
725
739
|
},
|
|
726
|
-
tableNames,
|
|
727
|
-
routes,
|
|
740
|
+
tableSamples: sample(tableNames, 40),
|
|
728
741
|
};
|
|
729
742
|
|
|
730
|
-
return
|
|
743
|
+
return jsonContent(payload);
|
|
731
744
|
},
|
|
732
745
|
);
|
|
733
746
|
|
|
@@ -754,6 +767,12 @@ server.tool(
|
|
|
754
767
|
const routeTables = new Set(routes.map((route) => route.mainTable).filter(Boolean));
|
|
755
768
|
const adminRoutes = routes.filter((route) => route.path?.startsWith('/admin'));
|
|
756
769
|
const publicRoutes = routes.filter((route) => route.publicMethods?.length);
|
|
770
|
+
const sample = (items, max = 25) => ({
|
|
771
|
+
total: items.length,
|
|
772
|
+
returned: Math.min(items.length, max),
|
|
773
|
+
items: items.slice(0, max),
|
|
774
|
+
truncated: items.length > max,
|
|
775
|
+
});
|
|
757
776
|
|
|
758
777
|
const payload = {
|
|
759
778
|
targetInstance: targetInstance(),
|
|
@@ -789,12 +808,12 @@ server.tool(
|
|
|
789
808
|
methods: (methodsResult?.data || []).map((method) => ({ id: method.id || method._id, name: method.name })),
|
|
790
809
|
routeRuntime: {
|
|
791
810
|
routePattern: 'GET/POST /<route-path>; PATCH/DELETE /<route-path>/:id; no dynamic GET /<route-path>/:id.',
|
|
792
|
-
adminRoutes: adminRoutes.map((route) => route.path).sort(),
|
|
793
|
-
publicRoutes: publicRoutes.map((route) => ({
|
|
811
|
+
adminRoutes: sample(adminRoutes.map((route) => route.path).sort()),
|
|
812
|
+
publicRoutes: sample(publicRoutes.map((route) => ({
|
|
794
813
|
path: route.path,
|
|
795
814
|
mainTable: route.mainTable,
|
|
796
815
|
publicMethods: route.publicMethods,
|
|
797
|
-
})),
|
|
816
|
+
}))),
|
|
798
817
|
},
|
|
799
818
|
cacheAndCluster: {
|
|
800
819
|
metadataMutationReloads: 'Metadata-backed mutations emit cache invalidation; admin reload endpoints exist for metadata/routes/graphql/guards/all.',
|
|
@@ -811,7 +830,7 @@ server.tool(
|
|
|
811
830
|
'MCP can test flow steps and websocket scripts through admin test endpoints, but not prove every production queue/client path without a real end-to-end client.',
|
|
812
831
|
].filter(Boolean),
|
|
813
832
|
};
|
|
814
|
-
return
|
|
833
|
+
return jsonContent(payload);
|
|
815
834
|
},
|
|
816
835
|
);
|
|
817
836
|
|
|
@@ -893,7 +912,7 @@ server.tool(
|
|
|
893
912
|
discoveryRule: 'When building a query, inspect table metadata first, then use relation propertyName and primary column from that metadata.',
|
|
894
913
|
};
|
|
895
914
|
|
|
896
|
-
return
|
|
915
|
+
return jsonContent(payload);
|
|
897
916
|
},
|
|
898
917
|
);
|
|
899
918
|
|
|
@@ -1033,7 +1052,7 @@ server.tool(
|
|
|
1033
1052
|
},
|
|
1034
1053
|
};
|
|
1035
1054
|
|
|
1036
|
-
return
|
|
1055
|
+
return jsonContent(payload);
|
|
1037
1056
|
},
|
|
1038
1057
|
);
|
|
1039
1058
|
|
|
@@ -1045,6 +1064,7 @@ server.tool(
|
|
|
1045
1064
|
'get_enfyra_api_context',
|
|
1046
1065
|
[
|
|
1047
1066
|
'Returns the resolved API base URL for this MCP session (env ENFYRA_API_URL).',
|
|
1067
|
+
'Use this as the cheap first target sanity check before broad discovery or mutations.',
|
|
1048
1068
|
'Use when the user asks which HTTP endpoint or full URL applies: combine enfyraApiUrl with paths from server instructions (GET/POST /{table}, PATCH/DELETE /{table}/{id}, no GET /{table}/{id}).',
|
|
1049
1069
|
'Auth: publicMethods on a route can allow a method without Bearer; otherwise JWT + routePermissions — see server instructions.',
|
|
1050
1070
|
'If path might differ from table name, use get_all_routes before asserting a URL.',
|
|
@@ -1056,6 +1076,7 @@ server.tool(
|
|
|
1056
1076
|
const base = ENFYRA_API_URL.replace(/\/$/, '');
|
|
1057
1077
|
const gql = buildGraphqlUrls(ENFYRA_API_URL);
|
|
1058
1078
|
const payload = {
|
|
1079
|
+
targetInstance: targetInstance(),
|
|
1059
1080
|
enfyraApiUrl: base,
|
|
1060
1081
|
graphqlHttpUrl: gql.graphqlHttpUrl,
|
|
1061
1082
|
graphqlSchemaUrl: gql.graphqlSchemaUrl,
|
|
@@ -1072,7 +1093,7 @@ server.tool(
|
|
|
1072
1093
|
pathResolution: 'Confirm route path with get_all_routes or metadata — path may not equal table name.',
|
|
1073
1094
|
note: 'Full tool→HTTP mapping is in MCP server instructions (shown to the model at connect).',
|
|
1074
1095
|
};
|
|
1075
|
-
return
|
|
1096
|
+
return jsonContent(payload);
|
|
1076
1097
|
},
|
|
1077
1098
|
);
|
|
1078
1099
|
|