@enfyra/mcp-server 0.1.65 → 0.1.67
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 +1 -0
- package/dist/lib/extension-search-tools.d.ts +15 -0
- package/dist/lib/extension-search-tools.js +32 -6
- package/dist/lib/extension-search-tools.js.map +1 -1
- package/dist/lib/mcp-instructions.js +3 -1
- package/dist/lib/mcp-instructions.js.map +1 -1
- package/dist/lib/model-eval.d.ts +4 -0
- package/dist/lib/model-eval.js +354 -0
- package/dist/lib/model-eval.js.map +1 -0
- package/dist/lib/pagination.d.ts +16 -0
- package/dist/lib/pagination.js +41 -0
- package/dist/lib/pagination.js.map +1 -0
- package/dist/lib/platform-operation-tools.d.ts +1 -0
- package/dist/lib/record-contracts.d.ts +13 -0
- package/dist/lib/record-contracts.js +33 -0
- package/dist/lib/record-contracts.js.map +1 -0
- package/dist/lib/required-knowledge.js +4 -2
- package/dist/lib/required-knowledge.js.map +1 -1
- package/dist/lib/response-format.d.ts +3 -1
- package/dist/lib/response-format.js +47 -17
- package/dist/lib/response-format.js.map +1 -1
- package/dist/lib/runtime-zone-tools.d.ts +30 -0
- package/dist/lib/runtime-zone-tools.js +26 -6
- package/dist/lib/runtime-zone-tools.js.map +1 -1
- package/dist/lib/session-safety.js +3 -26
- package/dist/lib/session-safety.js.map +1 -1
- package/dist/lib/source-artifacts.d.ts +7 -0
- package/dist/lib/source-artifacts.js +38 -2
- package/dist/lib/source-artifacts.js.map +1 -1
- package/dist/lib/tool-catalog.d.ts +7 -0
- package/dist/lib/tool-catalog.js +141 -0
- package/dist/lib/tool-catalog.js.map +1 -0
- package/dist/lib/tool-contracts.d.ts +6 -0
- package/dist/lib/tool-contracts.js +99 -0
- package/dist/lib/tool-contracts.js.map +1 -0
- package/dist/lib/tool-output-contracts.d.ts +7 -0
- package/dist/lib/tool-output-contracts.js +175 -0
- package/dist/lib/tool-output-contracts.js.map +1 -0
- package/dist/lib/tool-routing.d.ts +22 -2
- package/dist/lib/tool-routing.js +36 -9
- package/dist/lib/tool-routing.js.map +1 -1
- package/dist/lib/toolset-filter.d.ts +7 -6
- package/dist/lib/toolset-filter.js +79 -21
- package/dist/lib/toolset-filter.js.map +1 -1
- package/dist/lib/types.d.ts +77 -0
- package/dist/lib/workflow-tool-packs.d.ts +2 -0
- package/dist/lib/workflow-tool-packs.js +55 -0
- package/dist/lib/workflow-tool-packs.js.map +1 -0
- package/dist/mcp-server-entry.js +85 -13
- package/dist/mcp-server-entry.js.map +1 -1
- package/package.json +5 -2
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export const MCP_TOOLSETS = ['guided', 'full'];
|
|
2
2
|
export const MCP_PROFILES = ['all', 'extension', 'schema', 'runtime', 'operations'];
|
|
3
|
-
const CORE_TOOL_NAMES = [
|
|
3
|
+
export const CORE_TOOL_NAMES = [
|
|
4
4
|
'get_enfyra_required_knowledge',
|
|
5
5
|
'get_enfyra_examples',
|
|
6
6
|
'discover_enfyra_workflows',
|
|
@@ -11,15 +11,17 @@ const CORE_TOOL_NAMES = [
|
|
|
11
11
|
'get_enfyra_api_context',
|
|
12
12
|
'get_current_user',
|
|
13
13
|
'get_permission_profile',
|
|
14
|
+
'search_enfyra_tools',
|
|
15
|
+
'execute_enfyra_tool',
|
|
16
|
+
'select_enfyra_workflow',
|
|
14
17
|
];
|
|
18
|
+
const CORE_TOOL_SET = new Set(CORE_TOOL_NAMES);
|
|
15
19
|
const PROFILE_TOOL_NAMES = {
|
|
16
20
|
extension: [
|
|
17
21
|
...CORE_TOOL_NAMES,
|
|
18
22
|
'search_admin_extensions',
|
|
19
23
|
'search_runtime_zone',
|
|
20
24
|
'inspect_table',
|
|
21
|
-
'inspect_feature',
|
|
22
|
-
'trace_metadata_usage',
|
|
23
25
|
'get_table_metadata',
|
|
24
26
|
'query_table',
|
|
25
27
|
'count_records',
|
|
@@ -44,8 +46,6 @@ const PROFILE_TOOL_NAMES = {
|
|
|
44
46
|
'debug_field_exposure',
|
|
45
47
|
'inspect_table',
|
|
46
48
|
'inspect_route',
|
|
47
|
-
'inspect_feature',
|
|
48
|
-
'trace_metadata_usage',
|
|
49
49
|
'get_table_metadata',
|
|
50
50
|
'get_all_tables',
|
|
51
51
|
'get_schema_design_context',
|
|
@@ -72,7 +72,6 @@ const PROFILE_TOOL_NAMES = {
|
|
|
72
72
|
'search_runtime_zone',
|
|
73
73
|
'inspect_table',
|
|
74
74
|
'inspect_route',
|
|
75
|
-
'get_script_source',
|
|
76
75
|
'patch_script_source',
|
|
77
76
|
'update_script_source',
|
|
78
77
|
'validate_dynamic_script',
|
|
@@ -103,9 +102,6 @@ const PROFILE_TOOL_NAMES = {
|
|
|
103
102
|
'search_runtime_zone',
|
|
104
103
|
'inspect_table',
|
|
105
104
|
'inspect_route',
|
|
106
|
-
'inspect_feature',
|
|
107
|
-
'trace_metadata_usage',
|
|
108
|
-
'get_all_routes',
|
|
109
105
|
'query_table',
|
|
110
106
|
'count_records',
|
|
111
107
|
'find_one_record',
|
|
@@ -141,6 +137,16 @@ export function normalizeMcpProfile(value) {
|
|
|
141
137
|
const raw = String(value || '').trim().toLowerCase();
|
|
142
138
|
return MCP_PROFILES.includes(raw) ? raw : 'all';
|
|
143
139
|
}
|
|
140
|
+
export function normalizeDynamicToolPacks(value, toolset, profile) {
|
|
141
|
+
if (toolset === 'full' || profile !== 'all')
|
|
142
|
+
return false;
|
|
143
|
+
const raw = String(value ?? '').trim().toLowerCase();
|
|
144
|
+
if (['0', 'false', 'off', 'no'].includes(raw))
|
|
145
|
+
return false;
|
|
146
|
+
if (['1', 'true', 'on', 'yes'].includes(raw))
|
|
147
|
+
return true;
|
|
148
|
+
return true;
|
|
149
|
+
}
|
|
144
150
|
export function isToolVisibleInToolset(toolName, toolset, profile = 'all') {
|
|
145
151
|
if (toolset === 'full')
|
|
146
152
|
return true;
|
|
@@ -148,23 +154,65 @@ export function isToolVisibleInToolset(toolName, toolset, profile = 'all') {
|
|
|
148
154
|
return GUIDED_TOOL_NAMES.has(toolName);
|
|
149
155
|
return PROFILE_TOOL_SETS[profile].has(toolName);
|
|
150
156
|
}
|
|
151
|
-
export function installToolsetFilter(server, toolset, profile = 'all') {
|
|
157
|
+
export function installToolsetFilter(server, toolset, profile = 'all', { dynamic = false } = {}) {
|
|
152
158
|
const registerTool = server.tool.bind(server);
|
|
153
159
|
const hiddenTools = [];
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
+
const registrations = new Map();
|
|
161
|
+
const refreshHiddenTools = () => {
|
|
162
|
+
hiddenTools.splice(0, hiddenTools.length, ...[...registrations.values()]
|
|
163
|
+
.filter((tool) => !tool.visible)
|
|
164
|
+
.map((tool) => tool.name));
|
|
165
|
+
};
|
|
166
|
+
server.tool = (...args) => {
|
|
167
|
+
const name = String(args[0]);
|
|
168
|
+
const description = typeof args[1] === 'string' ? args[1] : '';
|
|
169
|
+
const inputSchema = (typeof args[1] === 'string' ? args[2] : args[1]) || {};
|
|
170
|
+
const handler = args.at(-1);
|
|
171
|
+
const annotations = args.length >= 5 ? args.at(-2) : undefined;
|
|
172
|
+
const eligible = isToolVisibleInToolset(name, toolset, profile);
|
|
173
|
+
const visible = eligible && (!dynamic || CORE_TOOL_SET.has(name));
|
|
174
|
+
const registration = registerTool(...args);
|
|
175
|
+
if (registration && !visible)
|
|
176
|
+
registration.enabled = false;
|
|
177
|
+
registrations.set(name, { name, description, inputSchema, annotations, handler, visible, registration });
|
|
178
|
+
refreshHiddenTools();
|
|
179
|
+
return registration;
|
|
160
180
|
};
|
|
161
|
-
|
|
181
|
+
const state = {
|
|
162
182
|
toolset,
|
|
163
183
|
profile,
|
|
184
|
+
dynamic,
|
|
164
185
|
hiddenTools,
|
|
186
|
+
getTool: (name) => registrations.get(name),
|
|
187
|
+
listTools: () => [...registrations.values()],
|
|
188
|
+
listVisibleToolNames: () => [...registrations.values()]
|
|
189
|
+
.filter((tool) => tool.visible)
|
|
190
|
+
.map((tool) => tool.name),
|
|
191
|
+
setActiveTools: (toolNames) => {
|
|
192
|
+
const requested = new Set(toolNames);
|
|
193
|
+
for (const coreTool of CORE_TOOL_NAMES)
|
|
194
|
+
requested.add(coreTool);
|
|
195
|
+
let changed = false;
|
|
196
|
+
for (const tool of registrations.values()) {
|
|
197
|
+
const visible = isToolVisibleInToolset(tool.name, toolset, profile)
|
|
198
|
+
&& (!dynamic || requested.has(tool.name));
|
|
199
|
+
if (tool.visible === visible)
|
|
200
|
+
continue;
|
|
201
|
+
tool.visible = visible;
|
|
202
|
+
if (tool.registration)
|
|
203
|
+
tool.registration.enabled = visible;
|
|
204
|
+
changed = true;
|
|
205
|
+
}
|
|
206
|
+
refreshHiddenTools();
|
|
207
|
+
if (changed)
|
|
208
|
+
server.sendToolListChanged?.();
|
|
209
|
+
const visibleToolNames = state.listVisibleToolNames();
|
|
210
|
+
return { changed, visibleToolNames, hiddenToolCount: hiddenTools.length };
|
|
211
|
+
},
|
|
165
212
|
};
|
|
213
|
+
return state;
|
|
166
214
|
}
|
|
167
|
-
export function summarizeToolsetForInstructions(toolset, profile = 'all') {
|
|
215
|
+
export function summarizeToolsetForInstructions(toolset, profile = 'all', dynamic = false) {
|
|
168
216
|
if (toolset === 'full') {
|
|
169
217
|
return 'Toolset mode: full. All Enfyra MCP tools are visible, including low-level escape hatches; domain profile filtering is disabled.';
|
|
170
218
|
}
|
|
@@ -172,13 +220,23 @@ export function summarizeToolsetForInstructions(toolset, profile = 'all') {
|
|
|
172
220
|
return [
|
|
173
221
|
`Toolset mode: guided, domain profile: ${profile}. Only normal ${profile} workflow tools and shared discovery/context tools are visible.`,
|
|
174
222
|
'Use this focused surface when the task belongs to one domain and lower context overhead is important.',
|
|
223
|
+
'Use search_enfyra_tools for hidden long-tail read-only tools; hidden mutations require the full toolset.',
|
|
175
224
|
'Set ENFYRA_MCP_PROFILE=all for the complete guided surface, or ENFYRA_MCP_TOOLSET=full only for expert debugging or compatibility work.',
|
|
176
225
|
].join(' ');
|
|
177
226
|
}
|
|
227
|
+
if (!dynamic) {
|
|
228
|
+
return [
|
|
229
|
+
'Toolset mode: guided, domain profile: all. The complete curated guided surface is visible.',
|
|
230
|
+
'Use discover_enfyra_workflows for routing and search_enfyra_tools for hidden long-tail read-only tools.',
|
|
231
|
+
'Set ENFYRA_MCP_DYNAMIC_TOOLS=on to start with a compact routing surface on hosts that refresh tools/list_changed.',
|
|
232
|
+
'Low-level escape hatches require ENFYRA_MCP_TOOLSET=full.',
|
|
233
|
+
].join(' ');
|
|
234
|
+
}
|
|
178
235
|
return [
|
|
179
|
-
'Toolset mode: guided, domain profile: all.
|
|
180
|
-
'
|
|
181
|
-
'Use
|
|
236
|
+
'Toolset mode: guided, domain profile: all. Dynamic workflow packs start with a compact routing surface.',
|
|
237
|
+
'Call select_enfyra_workflow with the task surface to expose the exact direct workflow tools for this session.',
|
|
238
|
+
'Use search_enfyra_tools for hidden long-tail read-only tools; hidden mutations require the full toolset.',
|
|
239
|
+
'Set ENFYRA_MCP_DYNAMIC_TOOLS=off or use ENFYRA_MCP_PROFILE=extension, schema, runtime, or operations as a static fallback for hosts that do not refresh tools/list_changed. Low-level escape hatches require ENFYRA_MCP_TOOLSET=full.',
|
|
182
240
|
].join(' ');
|
|
183
241
|
}
|
|
184
242
|
//# sourceMappingURL=toolset-filter.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toolset-filter.js","sourceRoot":"","sources":["../../src/lib/toolset-filter.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"toolset-filter.js","sourceRoot":"","sources":["../../src/lib/toolset-filter.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/types.d.ts
CHANGED
|
@@ -15,6 +15,83 @@ export interface ToolResult {
|
|
|
15
15
|
_meta?: Record<string, unknown>;
|
|
16
16
|
}
|
|
17
17
|
export type UnknownRecord = Record<string, unknown>;
|
|
18
|
+
export interface McpToolAnnotations {
|
|
19
|
+
title: string;
|
|
20
|
+
readOnlyHint: boolean;
|
|
21
|
+
destructiveHint: boolean;
|
|
22
|
+
idempotentHint: boolean;
|
|
23
|
+
openWorldHint: boolean;
|
|
24
|
+
}
|
|
25
|
+
export interface McpToolContract {
|
|
26
|
+
name: string;
|
|
27
|
+
annotations: McpToolAnnotations;
|
|
28
|
+
catalogExecutable: boolean;
|
|
29
|
+
}
|
|
30
|
+
export interface RegisteredToolDefinition {
|
|
31
|
+
name: string;
|
|
32
|
+
description: string;
|
|
33
|
+
inputSchema: Record<string, unknown>;
|
|
34
|
+
annotations?: McpToolAnnotations;
|
|
35
|
+
handler: (...args: any[]) => any;
|
|
36
|
+
visible: boolean;
|
|
37
|
+
registration?: {
|
|
38
|
+
enabled: boolean;
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
export interface ToolsetRegistrationState {
|
|
42
|
+
toolset: string;
|
|
43
|
+
profile: string;
|
|
44
|
+
dynamic: boolean;
|
|
45
|
+
hiddenTools: string[];
|
|
46
|
+
getTool(name: string): RegisteredToolDefinition | undefined;
|
|
47
|
+
listTools(): RegisteredToolDefinition[];
|
|
48
|
+
listVisibleToolNames(): string[];
|
|
49
|
+
setActiveTools(toolNames: Iterable<string>): {
|
|
50
|
+
changed: boolean;
|
|
51
|
+
visibleToolNames: string[];
|
|
52
|
+
hiddenToolCount: number;
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
export type ToolAvailabilityStatus = 'allowed' | 'denied' | 'unknown';
|
|
56
|
+
export interface ToolAvailability {
|
|
57
|
+
status: ToolAvailabilityStatus;
|
|
58
|
+
reason: string;
|
|
59
|
+
}
|
|
60
|
+
export interface ModelEvalTraceEvent {
|
|
61
|
+
tool: string;
|
|
62
|
+
arguments?: Record<string, unknown>;
|
|
63
|
+
result?: unknown;
|
|
64
|
+
isError?: boolean;
|
|
65
|
+
}
|
|
66
|
+
export interface ModelEvalRun {
|
|
67
|
+
scenarioId: string;
|
|
68
|
+
model: string;
|
|
69
|
+
events: ModelEvalTraceEvent[];
|
|
70
|
+
}
|
|
71
|
+
export interface ModelEvalScenario {
|
|
72
|
+
id: string;
|
|
73
|
+
prompt: string;
|
|
74
|
+
surface: string;
|
|
75
|
+
requiredToolGroups: string[][];
|
|
76
|
+
verificationTools: string[];
|
|
77
|
+
maxToolCalls: number;
|
|
78
|
+
mutationExpected: boolean;
|
|
79
|
+
destructiveExpected?: boolean;
|
|
80
|
+
}
|
|
81
|
+
export interface ModelEvalCheck {
|
|
82
|
+
key: string;
|
|
83
|
+
passed: boolean;
|
|
84
|
+
detail: string;
|
|
85
|
+
blocking?: boolean;
|
|
86
|
+
}
|
|
87
|
+
export interface ModelEvalScore {
|
|
88
|
+
scenarioId: string;
|
|
89
|
+
model: string;
|
|
90
|
+
score: number;
|
|
91
|
+
optimizationScore: number;
|
|
92
|
+
recommended: boolean;
|
|
93
|
+
checks: ModelEvalCheck[];
|
|
94
|
+
}
|
|
18
95
|
export interface MetadataContext {
|
|
19
96
|
dbType: "postgres" | "mysql" | "mongodb" | "mariadb" | "sqlite" | null;
|
|
20
97
|
enfyraVersion: string | null;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { jsonContent } from './response-format.js';
|
|
3
|
+
import { WORKFLOW_SURFACES, workflowToolNames } from './tool-routing.js';
|
|
4
|
+
const MAX_ACTIVE_WORKFLOWS = 2;
|
|
5
|
+
export function registerWorkflowToolPack(server, state) {
|
|
6
|
+
const activeSurfaces = new Set();
|
|
7
|
+
return server.tool('select_enfyra_workflow', [
|
|
8
|
+
'Select a workflow surface and expose its exact direct MCP tools for this stdio session.',
|
|
9
|
+
'Use replace for normal tasks, add only when one task genuinely spans two surfaces, and reset to return to the compact routing surface.',
|
|
10
|
+
'This changes tool visibility only; it does not grant permissions or bypass Enfyra PAT/RBAC.',
|
|
11
|
+
].join(' '), {
|
|
12
|
+
surface: z.enum(WORKFLOW_SURFACES).optional().describe('Required for replace/add. Omit only with mode=reset.'),
|
|
13
|
+
mode: z.enum(['replace', 'add', 'reset']).optional().default('replace'),
|
|
14
|
+
}, async ({ surface, mode }) => {
|
|
15
|
+
if (mode !== 'reset' && !surface)
|
|
16
|
+
throw new Error('surface is required when mode is replace or add.');
|
|
17
|
+
if (mode === 'reset') {
|
|
18
|
+
activeSurfaces.clear();
|
|
19
|
+
}
|
|
20
|
+
else if (mode === 'replace') {
|
|
21
|
+
activeSurfaces.clear();
|
|
22
|
+
activeSurfaces.add(surface);
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
activeSurfaces.add(surface);
|
|
26
|
+
if (activeSurfaces.size > MAX_ACTIVE_WORKFLOWS) {
|
|
27
|
+
activeSurfaces.delete(surface);
|
|
28
|
+
throw new Error(`At most ${MAX_ACTIVE_WORKFLOWS} workflow surfaces may be active. Use mode=replace or reset first.`);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
const packTools = [...activeSurfaces].flatMap(workflowToolNames);
|
|
32
|
+
const result = state.setActiveTools(packTools);
|
|
33
|
+
return jsonContent({
|
|
34
|
+
action: 'enfyra_workflow_selected',
|
|
35
|
+
mode,
|
|
36
|
+
dynamic: state.dynamic,
|
|
37
|
+
activeSurfaces: [...activeSurfaces],
|
|
38
|
+
visibleToolCount: result.visibleToolNames.length,
|
|
39
|
+
visibleTools: result.visibleToolNames,
|
|
40
|
+
hiddenToolCount: result.hiddenToolCount,
|
|
41
|
+
changed: result.changed,
|
|
42
|
+
guidance: state.dynamic
|
|
43
|
+
? [
|
|
44
|
+
'Refresh tools/list after this response if the host has not already processed notifications/tools/list_changed.',
|
|
45
|
+
'Call the newly visible workflow tools directly so their exact schemas, annotations, and safety gates remain active.',
|
|
46
|
+
'Use search_enfyra_tools only for hidden read-only long-tail helpers.',
|
|
47
|
+
]
|
|
48
|
+
: [
|
|
49
|
+
'Dynamic packs are disabled for this static profile/toolset; the configured profile remains visible.',
|
|
50
|
+
'Use ENFYRA_MCP_DYNAMIC_TOOLS=on with guided/all on hosts that support tools/list_changed.',
|
|
51
|
+
],
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=workflow-tool-packs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workflow-tool-packs.js","sourceRoot":"","sources":["../../src/lib/workflow-tool-packs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAwB,MAAM,mBAAmB,CAAC;AAG/F,MAAM,oBAAoB,GAAG,CAAC,CAAC;AAE/B,MAAM,UAAU,wBAAwB,CAAC,MAAW,EAAE,KAA+B;IACnF,MAAM,cAAc,GAAG,IAAI,GAAG,EAAmB,CAAC;IAElD,OAAO,MAAM,CAAC,IAAI,CAChB,wBAAwB,EACxB;QACE,yFAAyF;QACzF,wIAAwI;QACxI,6FAA6F;KAC9F,CAAC,IAAI,CAAC,GAAG,CAAC,EACX;QACE,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,sDAAsD,CAAC;QAC9G,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC;KACxE,EACD,KAAK,EAAE,EAAE,OAAO,EAAE,IAAI,EAAoE,EAAE,EAAE;QAC5F,IAAI,IAAI,KAAK,OAAO,IAAI,CAAC,OAAO;YAAE,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAC;QACtG,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;YACrB,cAAc,CAAC,KAAK,EAAE,CAAC;QACzB,CAAC;aAAM,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YAC9B,cAAc,CAAC,KAAK,EAAE,CAAC;YACvB,cAAc,CAAC,GAAG,CAAC,OAAQ,CAAC,CAAC;QAC/B,CAAC;aAAM,CAAC;YACN,cAAc,CAAC,GAAG,CAAC,OAAQ,CAAC,CAAC;YAC7B,IAAI,cAAc,CAAC,IAAI,GAAG,oBAAoB,EAAE,CAAC;gBAC/C,cAAc,CAAC,MAAM,CAAC,OAAQ,CAAC,CAAC;gBAChC,MAAM,IAAI,KAAK,CAAC,WAAW,oBAAoB,oEAAoE,CAAC,CAAC;YACvH,CAAC;QACH,CAAC;QAED,MAAM,SAAS,GAAG,CAAC,GAAG,cAAc,CAAC,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC;QACjE,MAAM,MAAM,GAAG,KAAK,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC;QAC/C,OAAO,WAAW,CAAC;YACjB,MAAM,EAAE,0BAA0B;YAClC,IAAI;YACJ,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,cAAc,EAAE,CAAC,GAAG,cAAc,CAAC;YACnC,gBAAgB,EAAE,MAAM,CAAC,gBAAgB,CAAC,MAAM;YAChD,YAAY,EAAE,MAAM,CAAC,gBAAgB;YACrC,eAAe,EAAE,MAAM,CAAC,eAAe;YACvC,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,QAAQ,EAAE,KAAK,CAAC,OAAO;gBACrB,CAAC,CAAC;oBACE,gHAAgH;oBAChH,qHAAqH;oBACrH,sEAAsE;iBACvE;gBACH,CAAC,CAAC;oBACE,qGAAqG;oBACrG,2FAA2F;iBAC5F;SACN,CAAC,CAAC;IACL,CAAC,CACF,CAAC;AACJ,CAAC"}
|
package/dist/mcp-server-entry.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { config } from 'dotenv';
|
|
5
5
|
config();
|
|
6
|
-
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
6
|
+
import { McpServer, ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
7
7
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
8
8
|
import { z } from 'zod';
|
|
9
9
|
import { createHash } from 'node:crypto';
|
|
@@ -68,17 +68,23 @@ import { assertCreateHandlerRouteBoundary } from './lib/dynamic-endpoint-contrac
|
|
|
68
68
|
import { assertGenericRecordMutationAllowed, parseRecordBatchData, parseRecordData, prepareRecordBatchMutation, prepareRecordMutation, validatePortableScriptSource, validateScriptSourceIfPresent } from './lib/mutation-guards.js';
|
|
69
69
|
import { assertDynamicCodeKnowledgeAck, assertDynamicCodeKnowledgeAckIf, assertExtensionKnowledgeAckIf, assertGlobalRulesAck, acknowledgeRequiredKnowledge, buildRequiredKnowledgePayload, dynamicCodeKnowledgeAckParam, extensionKnowledgeAckParam, globalRulesAckParam, } from './lib/required-knowledge.js';
|
|
70
70
|
import { validateMainTableRoutePath } from './lib/route-guards.js';
|
|
71
|
+
import { buildDeletePostcondition, buildQuerySchemaReceipt } from './lib/record-contracts.js';
|
|
71
72
|
import { installColumnarToolFormatter, jsonContent } from './lib/response-format.js';
|
|
72
73
|
import { startMcpUsageTelemetry } from './lib/mcp-usage-telemetry.js';
|
|
73
74
|
import { startRuntimeCacheSocket } from './lib/runtime-cache-socket.js';
|
|
74
75
|
import { executeSequentialBatch } from './lib/sequential-batch.js';
|
|
75
|
-
import { compactSourceFields, writeSourceArtifact } from './lib/source-artifacts.js';
|
|
76
|
-
import { installToolsetFilter, normalizeMcpProfile, normalizeMcpToolset, summarizeToolsetForInstructions } from './lib/toolset-filter.js';
|
|
76
|
+
import { compactSourceFields, readSourceArtifactResource, writeSourceArtifact } from './lib/source-artifacts.js';
|
|
77
|
+
import { installToolsetFilter, normalizeDynamicToolPacks, normalizeMcpProfile, normalizeMcpToolset, summarizeToolsetForInstructions } from './lib/toolset-filter.js';
|
|
78
|
+
import { installToolAnnotations } from './lib/tool-contracts.js';
|
|
79
|
+
import { installToolOutputContracts } from './lib/tool-output-contracts.js';
|
|
80
|
+
import { registerToolCatalogTools } from './lib/tool-catalog.js';
|
|
81
|
+
import { registerWorkflowToolPack } from './lib/workflow-tool-packs.js';
|
|
77
82
|
import { findRoutePermission, mergeMethodNames, normalizeMethodNames, resolveRoleByNameOrId, routeAvailableMethodNames, routePublicMethodNames, summarizeRouteAccess, summarizeRoutePermission, validateMethodsForRoute, } from './lib/route-permission-tools.js';
|
|
78
83
|
// Initialize auth module
|
|
79
84
|
initAuth(ENFYRA_API_URL, ENFYRA_API_TOKEN);
|
|
80
85
|
const MCP_TOOLSET = normalizeMcpToolset(process.env.ENFYRA_MCP_TOOLSET);
|
|
81
86
|
const MCP_PROFILE = normalizeMcpProfile(process.env.ENFYRA_MCP_PROFILE);
|
|
87
|
+
const MCP_DYNAMIC_TOOLS = normalizeDynamicToolPacks(process.env.ENFYRA_MCP_DYNAMIC_TOOLS, MCP_TOOLSET, MCP_PROFILE);
|
|
82
88
|
const CAPABILITY_AREAS = [
|
|
83
89
|
{
|
|
84
90
|
area: 'Schema and metadata',
|
|
@@ -418,6 +424,30 @@ function summarizePermissionProfile(user) {
|
|
|
418
424
|
})),
|
|
419
425
|
};
|
|
420
426
|
}
|
|
427
|
+
async function resolveCatalogToolAvailability(toolNames) {
|
|
428
|
+
const fields = DEFAULT_ME_PERMISSION_FIELDS.join(',');
|
|
429
|
+
const result = await fetchAPI(ENFYRA_API_URL, `/me?fields=${encodeURIComponent(fields)}`);
|
|
430
|
+
const user = firstDataRecord(result);
|
|
431
|
+
if (user?.isRootAdmin) {
|
|
432
|
+
return Object.fromEntries(toolNames.map((name) => [name, {
|
|
433
|
+
status: 'allowed',
|
|
434
|
+
reason: 'The configured PAT belongs to a root administrator.',
|
|
435
|
+
}]));
|
|
436
|
+
}
|
|
437
|
+
const requirements = summarizePermissionProfile(user).mcpRequirements;
|
|
438
|
+
return Object.fromEntries(toolNames.map((name) => {
|
|
439
|
+
const requirement = requirements.find((item) => item.tools.includes(name));
|
|
440
|
+
if (!requirement) {
|
|
441
|
+
return [name, {
|
|
442
|
+
status: 'unknown',
|
|
443
|
+
reason: 'No static admin-route capability mapping exists for this tool; Enfyra PAT/RBAC remains authoritative at execution time.',
|
|
444
|
+
}];
|
|
445
|
+
}
|
|
446
|
+
return [name, requirement.allowed
|
|
447
|
+
? { status: 'allowed', reason: `Current PAT grants ${requirement.methods.map((item) => item.method).join(', ')} ${requirement.route}.` }
|
|
448
|
+
: { status: 'denied', reason: `Current PAT lacks one or more required methods on ${requirement.route}.` }];
|
|
449
|
+
}));
|
|
450
|
+
}
|
|
421
451
|
function parseJsonArg(value, fallback = undefined) {
|
|
422
452
|
if (value === undefined || value === null || value === '')
|
|
423
453
|
return fallback;
|
|
@@ -503,10 +533,10 @@ function summarizeMutationResult(result, action, tableName) {
|
|
|
503
533
|
async function getTableSummary(tableName) {
|
|
504
534
|
return summarizeTable(await fetchTableMetadata(ENFYRA_API_URL, tableName));
|
|
505
535
|
}
|
|
506
|
-
async function getPrimaryFieldName(tableName) {
|
|
507
|
-
const
|
|
508
|
-
if (
|
|
509
|
-
return
|
|
536
|
+
async function getPrimaryFieldName(tableName, table = null) {
|
|
537
|
+
const resolvedTable = table ?? await getTableSummary(tableName);
|
|
538
|
+
if (resolvedTable?.primaryKey)
|
|
539
|
+
return resolvedTable.primaryKey;
|
|
510
540
|
const metadata = await fetchMetadataContext(ENFYRA_API_URL);
|
|
511
541
|
return metadata.dbType === 'mongodb' ? '_id' : 'id';
|
|
512
542
|
}
|
|
@@ -810,12 +840,19 @@ const server = new McpServer({
|
|
|
810
840
|
version: '1.0.0',
|
|
811
841
|
}, {
|
|
812
842
|
instructions: buildMcpServerInstructions(ENFYRA_API_URL, {
|
|
813
|
-
toolsetSummary: summarizeToolsetForInstructions(MCP_TOOLSET, MCP_PROFILE),
|
|
843
|
+
toolsetSummary: summarizeToolsetForInstructions(MCP_TOOLSET, MCP_PROFILE, MCP_DYNAMIC_TOOLS),
|
|
814
844
|
}),
|
|
815
845
|
});
|
|
846
|
+
installToolOutputContracts(server);
|
|
816
847
|
installColumnarToolFormatter(server);
|
|
817
|
-
installToolsetFilter(server, MCP_TOOLSET, MCP_PROFILE);
|
|
848
|
+
const toolsetState = installToolsetFilter(server, MCP_TOOLSET, MCP_PROFILE, { dynamic: MCP_DYNAMIC_TOOLS });
|
|
849
|
+
installToolAnnotations(server);
|
|
818
850
|
startMcpUsageTelemetry(ENFYRA_API_URL, `${MCP_TOOLSET}:${MCP_PROFILE}`);
|
|
851
|
+
server.registerResource('enfyra-source-artifact', new ResourceTemplate('enfyra-source://artifact/{artifactId}', { list: undefined }), {
|
|
852
|
+
title: 'Enfyra source artifact',
|
|
853
|
+
description: 'Process-scoped source or diff artifact created by an Enfyra MCP inspect or preview tool.',
|
|
854
|
+
mimeType: 'text/plain',
|
|
855
|
+
}, async (uri) => ({ contents: [readSourceArtifactResource(uri.href)] }));
|
|
819
856
|
// ============================================================================
|
|
820
857
|
// METADATA TOOLS
|
|
821
858
|
// ============================================================================
|
|
@@ -904,7 +941,7 @@ server.tool('discover_enfyra_workflows', [
|
|
|
904
941
|
risk: z.string().optional().default('unknown').describe('Highest expected operation risk. Preferred values: read, write, destructive, debug, unknown. Natural terms such as low, medium, or high are accepted and normalized.'),
|
|
905
942
|
detail: z.enum(['summary', 'plan', 'full']).optional().default('summary').describe('summary lists candidate workflows; plan adds tool sequence and avoidTools; full also includes matching keywords.'),
|
|
906
943
|
limit: z.number().int().positive().max(10).optional().default(5).describe('Maximum workflows to return.'),
|
|
907
|
-
}, async (input) => jsonContent(discoverWorkflowRoutes(input, MCP_PROFILE)));
|
|
944
|
+
}, async (input) => jsonContent(discoverWorkflowRoutes(input, MCP_PROFILE, MCP_DYNAMIC_TOOLS)));
|
|
908
945
|
server.tool('discover_enfyra_system', [
|
|
909
946
|
'Call this first when you need to understand the live Enfyra instance.',
|
|
910
947
|
'Returns a concise capability map from live metadata/routes/method rows, including schema management, REST route behavior, GraphQL enablement, and relation handling.',
|
|
@@ -1344,7 +1381,7 @@ server.tool('get_enfyra_api_context', [
|
|
|
1344
1381
|
};
|
|
1345
1382
|
return jsonContent(payload);
|
|
1346
1383
|
});
|
|
1347
|
-
server.tool('query_table', 'Query any route-backed table. Response is minimal unless fields is explicit. Every call must pass either limit or all=true. Use count_records or meta=filterCount/totalCount for counts; call discover_query_capabilities before using aggregate objects instead of guessing _sum/_count operators. For enfyra_extension, editable extension source is `code`, not `sourceCode`; prefer search_admin_extensions and patch_extension_code/update_extension_code for admin UI.', {
|
|
1384
|
+
server.tool('query_table', 'Query any route-backed table with a live metadata preflight. Explicit fields are validated before the REST read and the result includes schemaReceipt, so a separate metadata call is optional unless the schema itself must be inspected. Response is minimal unless fields is explicit. Every call must pass either limit or all=true. Use count_records or meta=filterCount/totalCount for counts; call discover_query_capabilities before using aggregate objects instead of guessing _sum/_count operators. For enfyra_extension, editable extension source is `code`, not `sourceCode`; prefer search_admin_extensions and patch_extension_code/update_extension_code for admin UI.', {
|
|
1348
1385
|
tableName: z.string().describe('Table name to query'),
|
|
1349
1386
|
filter: jsonObjectParam(z, 'Filter object').optional().describe('Filter object. Example: {"status": {"_eq": "active"}}.'),
|
|
1350
1387
|
sort: z.string().optional().describe('Sort field. Prefix with - for descending (e.g., "createdAt", "-id")'),
|
|
@@ -1371,9 +1408,12 @@ server.tool('query_table', 'Query any route-backed table. Response is minimal un
|
|
|
1371
1408
|
parseJsonArg(deep, undefined);
|
|
1372
1409
|
parseJsonArg(aggregate, undefined);
|
|
1373
1410
|
const queryParams = new URLSearchParams();
|
|
1374
|
-
const
|
|
1411
|
+
const table = await getTableSummary(tableName);
|
|
1412
|
+
const primaryKey = await getPrimaryFieldName(tableName, table);
|
|
1413
|
+
const requestedFields = fields && fields.length > 0 ? fields : [primaryKey];
|
|
1375
1414
|
const deepFieldSelection = applyDeepFieldSelections(requestedFields, deep);
|
|
1376
1415
|
const selectedFields = deepFieldSelection.fields;
|
|
1416
|
+
const schemaReceipt = buildQuerySchemaReceipt({ ...table, primaryKey }, selectedFields);
|
|
1377
1417
|
if (filterParam)
|
|
1378
1418
|
queryParams.set('filter', filterParam);
|
|
1379
1419
|
const normalizedSort = normalizeSortParam(sort);
|
|
@@ -1407,6 +1447,7 @@ server.tool('query_table', 'Query any route-backed table. Response is minimal un
|
|
|
1407
1447
|
aggregate: aggregate ? parseJsonArg(aggregate, null) : null,
|
|
1408
1448
|
},
|
|
1409
1449
|
minimalDefaultApplied: !(fields && fields.length > 0),
|
|
1450
|
+
schemaReceipt,
|
|
1410
1451
|
meta: result?.meta,
|
|
1411
1452
|
data: compactSourceFields(result?.data || [], { tableName }),
|
|
1412
1453
|
detailHint: fields && fields.length > 0
|
|
@@ -1753,7 +1794,7 @@ function isNotFoundDeleteError(error) {
|
|
|
1753
1794
|
|| message.includes('not exists')
|
|
1754
1795
|
|| message.includes('does not exist');
|
|
1755
1796
|
}
|
|
1756
|
-
server.tool('delete_records', 'Delete one or more route-backed records in one MCP call. Pass items as a native JSON array; for one delete, pass one item. The tool previews every target when confirm=false, rejects duplicate ids, and deletes sequentially when confirm=true. By default, confirm=true skips records that were already removed by cascade or a previous cleanup step.', {
|
|
1797
|
+
server.tool('delete_records', 'Delete one or more route-backed records in one MCP call. Pass items as a native JSON array; for one delete, pass one item. The tool previews every target when confirm=false, rejects duplicate ids, and deletes sequentially when confirm=true. Confirmed deletes automatically re-read the requested primary keys and return postcondition.confirmedAbsent plus remainingIds, so a separate absence query is optional. By default, confirm=true skips records that were already removed by cascade or a previous cleanup step.', {
|
|
1757
1798
|
tableName: z.string().describe('Table name'),
|
|
1758
1799
|
items: bulkObjectArrayParam(z, 'Delete items').describe('Native JSON array of delete items: [{ "id": "...", "queryParams": { ... }? }].'),
|
|
1759
1800
|
maxItems: z.number().int().min(1).max(100).optional().default(100).describe('Safety cap for one MCP batch. Default/max is 100.'),
|
|
@@ -1795,6 +1836,12 @@ server.tool('delete_records', 'Delete one or more route-backed records in one MC
|
|
|
1795
1836
|
duplicateIdsRejected: true,
|
|
1796
1837
|
destructive: true,
|
|
1797
1838
|
previews,
|
|
1839
|
+
postcondition: {
|
|
1840
|
+
verificationMethod: 'not_run_preview',
|
|
1841
|
+
requestedIds: parsedItems.map((item) => item.id),
|
|
1842
|
+
remainingIds: previews.filter((item) => item.preview).map((item) => item.id),
|
|
1843
|
+
confirmedAbsent: false,
|
|
1844
|
+
},
|
|
1798
1845
|
next: 'Call delete_records again with the same items and confirm=true to delete these route-backed records sequentially.',
|
|
1799
1846
|
}, null, 2) }] };
|
|
1800
1847
|
}
|
|
@@ -1825,6 +1872,26 @@ server.tool('delete_records', 'Delete one or more route-backed records in one MC
|
|
|
1825
1872
|
throw error;
|
|
1826
1873
|
}
|
|
1827
1874
|
}
|
|
1875
|
+
const requestedIds = parsedItems.map((item) => item.id);
|
|
1876
|
+
let postcondition;
|
|
1877
|
+
try {
|
|
1878
|
+
const verificationQuery = new URLSearchParams({
|
|
1879
|
+
filter: JSON.stringify({ [primaryKey]: { _in: requestedIds } }),
|
|
1880
|
+
limit: String(parsedItems.length),
|
|
1881
|
+
fields: primaryKey,
|
|
1882
|
+
});
|
|
1883
|
+
const verification = await fetchAPI(ENFYRA_API_URL, `/${tableName}?${verificationQuery.toString()}`);
|
|
1884
|
+
postcondition = buildDeletePostcondition(requestedIds, verification?.data ?? [], primaryKey);
|
|
1885
|
+
}
|
|
1886
|
+
catch (error) {
|
|
1887
|
+
postcondition = {
|
|
1888
|
+
verificationMethod: 'route_read_by_primary_keys',
|
|
1889
|
+
requestedIds,
|
|
1890
|
+
remainingIds: [],
|
|
1891
|
+
confirmedAbsent: false,
|
|
1892
|
+
verificationError: String(error?.message || error),
|
|
1893
|
+
};
|
|
1894
|
+
}
|
|
1828
1895
|
return { content: [{ type: 'text', text: JSON.stringify({
|
|
1829
1896
|
action: 'deleted_records',
|
|
1830
1897
|
tableName,
|
|
@@ -1836,6 +1903,7 @@ server.tool('delete_records', 'Delete one or more route-backed records in one MC
|
|
|
1836
1903
|
skipNotFound,
|
|
1837
1904
|
deleted,
|
|
1838
1905
|
skippedNotFound,
|
|
1906
|
+
postcondition,
|
|
1839
1907
|
}, null, 2) }] };
|
|
1840
1908
|
});
|
|
1841
1909
|
server.tool('list_methods', 'List enfyra_method records with their UI colors. Use this before creating route methods or method-colored UI.', {}, async () => {
|
|
@@ -3150,6 +3218,10 @@ server.tool('install_package', [
|
|
|
3150
3218
|
result,
|
|
3151
3219
|
});
|
|
3152
3220
|
});
|
|
3221
|
+
registerToolCatalogTools(server, toolsetState, {
|
|
3222
|
+
resolveAvailability: resolveCatalogToolAvailability,
|
|
3223
|
+
});
|
|
3224
|
+
registerWorkflowToolPack(server, toolsetState);
|
|
3153
3225
|
// ============================================================================
|
|
3154
3226
|
// MAIN
|
|
3155
3227
|
// ============================================================================
|