@enfyra/mcp-server 0.0.97 → 0.0.99
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/README.md +3 -0
- package/package.json +1 -1
- package/src/lib/mcp-examples.js +19 -24
- package/src/lib/mcp-instructions.js +3 -1
- package/src/lib/platform-operation-tools.js +1221 -0
- package/src/mcp-server-entry.mjs +2 -63
package/src/mcp-server-entry.mjs
CHANGED
|
@@ -21,6 +21,7 @@ import { fetchAPI, validateFilter, validateTableName } from './lib/fetch.js';
|
|
|
21
21
|
import { buildMcpServerInstructions, buildGraphqlUrls } from './lib/mcp-instructions.js';
|
|
22
22
|
import { getExamples, listExampleCategories } from './lib/mcp-examples.js';
|
|
23
23
|
import { registerTableTools } from './lib/table-tools.js';
|
|
24
|
+
import { registerPlatformOperationTools } from './lib/platform-operation-tools.js';
|
|
24
25
|
import { prepareRecordMutation, validateScriptSourceIfPresent } from './lib/mutation-guards.js';
|
|
25
26
|
import { validateMainTableRoutePath } from './lib/route-guards.js';
|
|
26
27
|
import { installColumnarToolFormatter, jsonContent } from './lib/response-format.js';
|
|
@@ -2841,6 +2842,7 @@ server.tool(
|
|
|
2841
2842
|
|
|
2842
2843
|
// Register table tools
|
|
2843
2844
|
registerTableTools(server, ENFYRA_API_URL);
|
|
2845
|
+
registerPlatformOperationTools(server, ENFYRA_API_URL);
|
|
2844
2846
|
|
|
2845
2847
|
// ============================================================================
|
|
2846
2848
|
// CACHE & SYSTEM TOOLS
|
|
@@ -3052,69 +3054,6 @@ server.tool(
|
|
|
3052
3054
|
},
|
|
3053
3055
|
);
|
|
3054
3056
|
|
|
3055
|
-
// ============================================================================
|
|
3056
|
-
// MENU & EXTENSION TOOLS
|
|
3057
|
-
// ============================================================================
|
|
3058
|
-
|
|
3059
|
-
server.tool('create_menu', 'Create a menu item in the navigation. Use permission JSON for sensitive menu visibility; successful writes should trigger the app menu reload contract.', {
|
|
3060
|
-
label: z.string().describe('Menu label'),
|
|
3061
|
-
type: z.enum(['Menu', 'Dropdown Menu']).default('Menu').describe('Menu type: "Menu" for leaf items, "Dropdown Menu" for items with children'),
|
|
3062
|
-
icon: z.string().optional().describe('Lucide icon name'),
|
|
3063
|
-
path: z.string().optional().describe('App route path for a clickable menu item, e.g. "/reports".'),
|
|
3064
|
-
externalUrl: z.string().optional().describe('External URL for a menu item when the backend supports external links.'),
|
|
3065
|
-
order: z.number().optional().default(0).describe('Display order'),
|
|
3066
|
-
isEnabled: z.boolean().optional().default(true).describe('Enable menu'),
|
|
3067
|
-
description: z.string().optional().describe('Menu description'),
|
|
3068
|
-
permission: z.string().optional().describe('Optional menu visibility permission JSON object string, e.g. {"or":[{"route":"/reports","methods":["GET"]}]}'),
|
|
3069
|
-
}, async (data) => {
|
|
3070
|
-
const body = { ...data };
|
|
3071
|
-
if (body.permission !== undefined) {
|
|
3072
|
-
body.permission = parseJsonArg(body.permission);
|
|
3073
|
-
if (!body.permission || typeof body.permission !== 'object' || Array.isArray(body.permission)) {
|
|
3074
|
-
throw new Error('permission must be a JSON object string.');
|
|
3075
|
-
}
|
|
3076
|
-
}
|
|
3077
|
-
if (body.path && !body.path.startsWith('/')) {
|
|
3078
|
-
body.path = '/' + body.path;
|
|
3079
|
-
}
|
|
3080
|
-
const result = await fetchAPI(ENFYRA_API_URL, '/enfyra_menu', { method: 'POST', body: JSON.stringify(body) });
|
|
3081
|
-
const created = firstDataRecord(result);
|
|
3082
|
-
return { content: [{ type: 'text', text: `Menu created (ID: ${getId(created)}):\n${JSON.stringify(result, null, 2)}` }] };
|
|
3083
|
-
});
|
|
3084
|
-
|
|
3085
|
-
server.tool(
|
|
3086
|
-
'create_extension',
|
|
3087
|
-
[
|
|
3088
|
-
'Create an extension (Vue SFC page, widget, or global shell extension). Code must be Vue SFC: <template>...</template> + <script setup>...</script> — NO imports, use globals (ref, useToast, useApi, UButton, etc).',
|
|
3089
|
-
'For type=page: create menu first (create_menu), get id, then pass menuId. For type=widget: no menu, embed via <Widget>. For type=global: no menu, the Enfyra admin UI mounts it invisibly at shell level for registries/realtime. Server auto-compiles and should emit realtime reload to open Enfyra admin tabs. See extension rules in MCP instructions.',
|
|
3090
|
-
].join(' '),
|
|
3091
|
-
{
|
|
3092
|
-
name: z.string().describe('Extension name (unique)'),
|
|
3093
|
-
type: z.enum(['page', 'widget', 'global']).describe('Extension type: page = full page linked to menu; widget = embed via Widget component; global = shell-level lifecycle component'),
|
|
3094
|
-
code: z.string().describe('Vue SFC string — <template> + <script setup>, NO import statements'),
|
|
3095
|
-
menuId: z.string().optional().describe('Required for type=page — enfyra_menu id from create_menu. Omit for widget/global'),
|
|
3096
|
-
isEnabled: z.boolean().optional().default(true).describe('Enable extension'),
|
|
3097
|
-
description: z.string().optional().describe('Extension description'),
|
|
3098
|
-
version: z.string().optional().default('1.0.0').describe('Extension version'),
|
|
3099
|
-
},
|
|
3100
|
-
async (data) => {
|
|
3101
|
-
const body = { ...data };
|
|
3102
|
-
if (body.type === 'page' && !body.menuId) {
|
|
3103
|
-
throw new Error('menuId is required for type=page. Create or find a enfyra_menu record first.');
|
|
3104
|
-
}
|
|
3105
|
-
if (body.type !== 'page' && body.menuId) {
|
|
3106
|
-
throw new Error('menuId is only valid for type=page. Omit menuId for widget/global extensions.');
|
|
3107
|
-
}
|
|
3108
|
-
if (body.menuId) {
|
|
3109
|
-
body.menu = { id: body.menuId };
|
|
3110
|
-
delete body.menuId;
|
|
3111
|
-
}
|
|
3112
|
-
const result = await fetchAPI(ENFYRA_API_URL, '/enfyra_extension', { method: 'POST', body: JSON.stringify(body) });
|
|
3113
|
-
const created = firstDataRecord(result);
|
|
3114
|
-
return { content: [{ type: 'text', text: `Extension created (ID: ${getId(created)}). Open Enfyra admin tabs should update through the realtime reload contract.\n${JSON.stringify(result, null, 2)}` }] };
|
|
3115
|
-
},
|
|
3116
|
-
);
|
|
3117
|
-
|
|
3118
3057
|
// ============================================================================
|
|
3119
3058
|
// MAIN
|
|
3120
3059
|
// ============================================================================
|