@enfyra/mcp-server 0.0.91 → 0.0.92
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 -1
- package/src/mcp-server-entry.mjs +35 -14
package/package.json
CHANGED
|
@@ -24,7 +24,7 @@ export function buildMcpServerInstructions(apiBaseUrl) {
|
|
|
24
24
|
`GraphQL endpoints: \`${graphqlHttpUrl}\` and \`${graphqlSchemaUrl}\`.`,
|
|
25
25
|
'',
|
|
26
26
|
'### Work Flow',
|
|
27
|
-
'- 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`.',
|
|
27
|
+
'- 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
28
|
'- Inspect narrowly. Use `inspect_table`, `inspect_route`, and `inspect_feature` for the table/route/feature being changed instead of loading broad metadata.',
|
|
29
29
|
'- 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.',
|
|
30
30
|
'- For server scripts, call `discover_script_contexts` before writing or reviewing handler/hook/flow/websocket/GraphQL logic.',
|
package/src/mcp-server-entry.mjs
CHANGED
|
@@ -353,6 +353,13 @@ async function fetchAll(path) {
|
|
|
353
353
|
return unwrapData(await fetchAPI(ENFYRA_API_URL, path));
|
|
354
354
|
}
|
|
355
355
|
|
|
356
|
+
function targetInstance() {
|
|
357
|
+
return {
|
|
358
|
+
apiBase: ENFYRA_API_URL.replace(/\/$/, ''),
|
|
359
|
+
source: 'ENFYRA_API_URL environment variable used by this MCP server process',
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
|
|
356
363
|
async function getMetadataTables() {
|
|
357
364
|
const metadata = await fetchAPI(ENFYRA_API_URL, '/metadata');
|
|
358
365
|
return {
|
|
@@ -617,6 +624,7 @@ server.tool(
|
|
|
617
624
|
[
|
|
618
625
|
'Call this first when you need to understand the live Enfyra instance.',
|
|
619
626
|
'Returns a concise capability map from live metadata/routes/method rows, including schema management, REST route behavior, GraphQL enablement, and relation handling.',
|
|
627
|
+
'Run broad discovery tools sequentially; do not call multiple broad discovery tools in parallel.',
|
|
620
628
|
].join(' '),
|
|
621
629
|
{},
|
|
622
630
|
async () => {
|
|
@@ -637,6 +645,7 @@ server.tool(
|
|
|
637
645
|
const routeTableList = [...routeTables].sort();
|
|
638
646
|
|
|
639
647
|
const payload = {
|
|
648
|
+
targetInstance: targetInstance(),
|
|
640
649
|
apiBase: ENFYRA_API_URL.replace(/\/$/, ''),
|
|
641
650
|
counts: {
|
|
642
651
|
tables: tableNames.length,
|
|
@@ -696,7 +705,7 @@ server.tool(
|
|
|
696
705
|
'discover_runtime_context',
|
|
697
706
|
[
|
|
698
707
|
'Discover live runtime context that affects how an LLM should use Enfyra.',
|
|
699
|
-
'Reports inferred primary key/backend family, route/cache/admin surfaces, active metadata-backed runtime areas, and what is not exposed by the backend API.',
|
|
708
|
+
'Reports inferred primary key/backend family, route/cache/admin surfaces, active metadata-backed runtime areas, and what is not exposed by the backend API. Run broad discovery tools sequentially; do not call multiple broad discovery tools in parallel.',
|
|
700
709
|
].join(' '),
|
|
701
710
|
{},
|
|
702
711
|
async () => {
|
|
@@ -728,6 +737,7 @@ server.tool(
|
|
|
728
737
|
const publicRoutes = routes.filter((route) => route.publicMethods?.length);
|
|
729
738
|
|
|
730
739
|
const payload = {
|
|
740
|
+
targetInstance: targetInstance(),
|
|
731
741
|
apiBase: ENFYRA_API_URL.replace(/\/$/, ''),
|
|
732
742
|
authenticatedUser: Array.isArray(meResult?.data) ? meResult.data[0] || null : meResult?.data || null,
|
|
733
743
|
database: getMetadataDatabaseContext(metadata, tables),
|
|
@@ -779,7 +789,7 @@ server.tool(
|
|
|
779
789
|
'discover_query_capabilities',
|
|
780
790
|
[
|
|
781
791
|
'Discover Enfyra query/filter/deep-fetch capabilities for the live instance.',
|
|
782
|
-
'
|
|
792
|
+
'Prefer passing tableName. Without tableName this returns only generic query rules. Run broad discovery tools sequentially; do not call multiple broad discovery tools in parallel.',
|
|
783
793
|
].join(' '),
|
|
784
794
|
{
|
|
785
795
|
tableName: z.string().optional().describe('Optional table name to summarize query fields and relation/deep capabilities.'),
|
|
@@ -796,6 +806,7 @@ server.tool(
|
|
|
796
806
|
: [];
|
|
797
807
|
|
|
798
808
|
const payload = {
|
|
809
|
+
targetInstance: targetInstance(),
|
|
799
810
|
operators: {
|
|
800
811
|
filter: FILTER_OPERATORS,
|
|
801
812
|
fieldPermissionConditions: FIELD_PERMISSION_CONDITION_OPERATORS,
|
|
@@ -859,11 +870,12 @@ server.tool(
|
|
|
859
870
|
'discover_script_contexts',
|
|
860
871
|
[
|
|
861
872
|
'Discover runtime script contexts and macro availability for handlers, hooks, flows, websocket scripts, GraphQL, packages, and extensions.',
|
|
862
|
-
'Use before writing dynamic JavaScript logic so the model does not mix context variables across surfaces.',
|
|
873
|
+
'Use before writing dynamic JavaScript logic so the model does not mix context variables across surfaces. This tool is static and safe to call alone; avoid running it in parallel with other broad discovery calls.',
|
|
863
874
|
].join(' '),
|
|
864
875
|
{},
|
|
865
876
|
async () => {
|
|
866
877
|
const payload = {
|
|
878
|
+
targetInstance: targetInstance(),
|
|
867
879
|
transformer: {
|
|
868
880
|
rule: 'Dynamic server scripts are transformed before sandbox execution. Macros expand to $ctx paths; comments are not transformed.',
|
|
869
881
|
preferredSyntax: 'Prefer template macros in generated Enfyra scripts. Use macros such as @BODY/@QUERY/@PARAMS/@USER/@REQ/@RES/@REPOS/@CACHE/@HELPERS/@FETCH/@STORAGE/@UPLOADED_FILE/@SOCKET/@TRIGGER/@DATA/@ERROR/@STATUS/@ENV/@PKGS/@LOGS/@SHARE/@API/@THROW* instead of raw $ctx access whenever a macro exists. Use raw $ctx only for fields without a macro.',
|
|
@@ -1844,14 +1856,20 @@ server.tool(
|
|
|
1844
1856
|
'inspect_feature',
|
|
1845
1857
|
[
|
|
1846
1858
|
'Search live REST/system metadata for a feature name, route path, table, handler, hook, guard, or permission.',
|
|
1847
|
-
'Use when the user mentions a capability and you need to find where it lives before editing.',
|
|
1859
|
+
'Use when the user mentions a capability and you need to find where it lives before editing. Keep the query specific; broad searches return bounded summaries.',
|
|
1848
1860
|
].join(' '),
|
|
1849
1861
|
{
|
|
1850
1862
|
query: z.string().describe('Feature keyword, table name, route path, handler text, hook name, or guard name'),
|
|
1863
|
+
limit: z.number().int().positive().max(25).optional().default(8).describe('Maximum matches returned per section. Default 8 to keep output small.'),
|
|
1851
1864
|
},
|
|
1852
|
-
async ({ query }) => {
|
|
1865
|
+
async ({ query, limit }) => {
|
|
1866
|
+
const rawQuery = String(query || '').trim();
|
|
1867
|
+
if (rawQuery.length < 2) {
|
|
1868
|
+
throw new Error('inspect_feature query must be at least 2 characters. Use a table name, route path, event name, or specific feature keyword.');
|
|
1869
|
+
}
|
|
1870
|
+
const max = Math.max(1, Math.min(Number(limit || 8), 25));
|
|
1853
1871
|
const state = await collectRestDefinitionState();
|
|
1854
|
-
const q =
|
|
1872
|
+
const q = rawQuery.toLowerCase();
|
|
1855
1873
|
const matchesText = (value) => JSON.stringify(value ?? '').toLowerCase().includes(q);
|
|
1856
1874
|
const tableMatches = state.tables.filter((table) => matchesText({
|
|
1857
1875
|
name: table.name,
|
|
@@ -1871,7 +1889,9 @@ server.tool(
|
|
|
1871
1889
|
];
|
|
1872
1890
|
|
|
1873
1891
|
const payload = {
|
|
1874
|
-
|
|
1892
|
+
targetInstance: targetInstance(),
|
|
1893
|
+
query: rawQuery,
|
|
1894
|
+
limit: max,
|
|
1875
1895
|
counts: {
|
|
1876
1896
|
tables: tableMatches.length,
|
|
1877
1897
|
routes: routeMatches.length,
|
|
@@ -1881,13 +1901,14 @@ server.tool(
|
|
|
1881
1901
|
guards: guardMatches.length,
|
|
1882
1902
|
permissions: permissionMatches.length,
|
|
1883
1903
|
},
|
|
1884
|
-
tables: tableMatches.
|
|
1885
|
-
routes: routeMatches.map((route) => enrichRoute(route, state))
|
|
1886
|
-
handlers: handlerMatches.slice(0,
|
|
1887
|
-
preHooks: preHookMatches.slice(0,
|
|
1888
|
-
postHooks: postHookMatches.slice(0,
|
|
1889
|
-
guards: guardMatches.slice(0,
|
|
1890
|
-
permissions: permissionMatches.slice(0,
|
|
1904
|
+
tables: tableMatches.slice(0, max).map(summarizeTable),
|
|
1905
|
+
routes: routeMatches.slice(0, max).map((route) => enrichRoute(route, state)),
|
|
1906
|
+
handlers: handlerMatches.slice(0, max),
|
|
1907
|
+
preHooks: preHookMatches.slice(0, max),
|
|
1908
|
+
postHooks: postHookMatches.slice(0, max),
|
|
1909
|
+
guards: guardMatches.slice(0, max),
|
|
1910
|
+
permissions: permissionMatches.slice(0, max),
|
|
1911
|
+
detailHint: 'For a specific match, call inspect_table, inspect_route, trace_metadata_usage, or get_script_source instead of broadening this search.',
|
|
1891
1912
|
};
|
|
1892
1913
|
|
|
1893
1914
|
return { content: [{ type: 'text', text: JSON.stringify(payload, null, 2) }] };
|